
/* Generated by Interface Builder */

#import "defs.h"
#import "Contour.h"
#import <appkit/Button.h>
#import <appkit/OpenPanel.h>
#import <appkit/Matrix.h>
#import <appkit/Cell.h>
#import <appkit/Pasteboard.h>
#import <appkit/Application.h>
#import <appkit/NXColorWell.h>
#import <appkit/color.h>
#import <objc/Storage.h>
#import <math.h>
#import <strings.h>
#import <defaults/defaults.h>
#import <streams/streams.h>
#import <sys/types.h>
#import <sys/stat.h>
#import "TextView.h"

@implementation Contour

/* Public methods */

+ initialize
/* Initializes the defaults. */
{
    const NXDefaultsVector NeXTcontourDefaults = {
	{ "Two_D", "NO" },
        { "AeroDynamics", "YES"},
        { "Binary_Data", "YES"},
        { "number_Of_Functions_Read_In", "5"},
        { "colorOption", "NO"},
        { "printColorMode", "NO"},
	{ NULL, NULL }
    };
      
    NXRegisterDefaults("NeXTcontour", NeXTcontourDefaults);

    return self;
  }

+ new
{
  const char *validSendTypes[2];

  self = [[super alloc] init];
  openPanel  = [OpenPanel new];

  validSendTypes[0] = NXAsciiPboardType;
  validSendTypes[1] = NULL;
  [NXApp registerServicesMenuSendTypes:validSendTypes andReturnTypes:NULL];
  [NXApp setDelegate:self];
  return self;
}

- appWillInit:sender
{

  /*  get default parameters and reset buttons */

  NXUpdateDefaults();

  /* Initialize defaults */
  Two_D = strncmp(NXGetDefaultValue("NeXTcontour", "Two_D"),"YES",3)==0 ?
  YES: NO;

  number_Of_Functions_Read_In = 
    strncmp(NXGetDefaultValue("NeXTcontour", "number_Of_Functions_Read_In"),
	    "4",3) ==0 ? 4: 1;

  colorOption = strncmp(NXGetDefaultValue("NeXTcontour", "colorOption"),
			"YES",3)==0 ? YES: NO;

  printColorMode = 
    strncmp(NXGetDefaultValue("NeXTcontour", "printColorMode"),
	    "YES",3)==0 ? YES: NO;

  AeroDynamic_Functions = 
    strncmp(NXGetDefaultValue("NeXTcontour", "AeroDynamics"),
			"YES",3)==0 ? YES: NO;

  Binary_Data_Type = 
    strncmp(NXGetDefaultValue("NeXTcontour", "Binary_Data"),
			"YES",3)==0 ? YES: NO;

  if(Two_D){
    [choose2D3DData setState:1];
    [choose2D3DGrid setState:1];
    [setDefault2D3D  setState:1];
    if(AeroDynamic_Functions){
      [setDefaultNumberOfFunctions setIntValue:4 at:0];
      [numberOfFunctions setIntValue:4 at:0];
      number_Of_Functions_Read_In = 4;
    }
  }

  if(!Two_D){
    [choose2D3DData setState:0];
    [choose2D3DGrid setState:0];
    [setDefault2D3D  setState:0];
    if(AeroDynamic_Functions){
      [setDefaultNumberOfFunctions setIntValue:5 at:0];
      [numberOfFunctions setIntValue:5 at:0];
      number_Of_Functions_Read_In = 5;
    }
  }

  if(AeroDynamic_Functions){
    [chooseDiscipline setState:0];
    [setDefaultDiscipline setState:0];
  }

  if(!AeroDynamic_Functions){
    [chooseDiscipline setState:1];
    [setDefaultDiscipline setState:1];
    [setDefaultNumberOfFunctions setIntValue:number_Of_Functions_Read_In at:0];
    [numberOfFunctions setIntValue:number_Of_Functions_Read_In at:0];
  }

  if(Binary_Data_Type){
    [chooseDataType setState:0];
    [setDefaultDataForm setState:0];
  }

  if(!Binary_Data_Type){
    [chooseDataType setState:1];
    [setDefaultDataForm setState:1];
  }

  if(colorOption){
    [setDefaultColor setState:0];
    [contourLineColor selectCellAt:0:3];
  }
  if(!colorOption){
    [setDefaultColor setState:1];
    [contourLineColor selectCellAt:0:2];
  }

  if(printColorMode){
    [setDefaultPrintColor setState:1];
    [printColor setState:1];
  }
  if(!printColorMode){
    [setDefaultPrintColor setState:0];
    [printColor setState:0];
  }

  [setDefault2D3D display];
  [setDefaultColor display];
  [setDefaultPrintColor display];
  [printColor display];
  [setDefaultDiscipline display];
  [chooseDiscipline display];
  [choose2D3DData display];
  [choose2D3DGrid display];

  if(colorOption)
    {
      [backgroundColor setColor:NX_COLORBLACK];
      [foregroundColor setColor:NX_COLORWHITE];
      [gridLineColor   setColor:NX_COLORLTGRAY];
    }
  if(!colorOption)
    {
      [foregroundColor setColor:NX_COLORBLACK];
      [backgroundColor setColor:NX_COLORWHITE];
      [gridLineColor   setColor:NX_COLORLTGRAY];
    }

  gridIsReadIn = NO;
  solutionIsReadIn = NO;
  oldMin.x = 0.0;
  oldMin.y = 0.0;
  oldMax.x = 1.0;
  oldMax.y = 1.0;
  currentMin.x = 0.0;
  currentMin.y = 0.0;
  currentMax.x = 1.0;
  currentMax.y = 1.0;

  [canvasWindow getFrame:&oldFrame];

  return self;
}

- appDidInit:sender
{
  [canvasWindow     setMiniwindowIcon:"NeXTcontour.tiff"];
  [controlsPanel    setMiniwindowIcon:"NeXTcontour.tiff"];
  [preferencesPanel setMiniwindowIcon:"NeXTcontour.tiff"];
  [subsetsPanel     setMiniwindowIcon:"NeXTcontour.tiff"];
  [colorPanel       setMiniwindowIcon:"NeXTcontour.tiff"];
  [helpPanel        setMiniwindowIcon:"NeXTcontour.tiff"];
  [levelsPanel      setMiniwindowIcon:"NeXTcontour.tiff"];

  return self;
}

- resetDefaults:sender
{
  int s1 = [setDefault2D3D state];
  int s2 = [setDefaultDiscipline state];
  int s3 = [setDefaultColor state];
  int s4 = [setDefaultPrintColor state];
  int s5 = [setDefaultDataForm state];
  char s[4];

  s[0] = '5';
  s[1] = '\0';
  s[2] = '\0';
  s[3] = '\0';

  switch(s1){
  case 0:
    Two_D = NO;
    NXWriteDefault("NeXTcontour", "Two_D", "NO");
    [choose2D3DData setState:0];
    [choose2D3DGrid setState:0]; 
   break;
  case 1:
    Two_D = YES;
    NXWriteDefault("NeXTcontour", "Two_D", "YES");
    [choose2D3DData setState:1];
    [choose2D3DGrid setState:1];
    break;
  }

  switch(s2){
  case 0:
    AeroDynamic_Functions = YES;
    NXWriteDefault("NeXTcontour", "AeroDynamics", "YES");
    [chooseDiscipline setState:0];
    if(Two_D){
      [setDefaultNumberOfFunctions setIntValue:4 at:0];
      number_Of_Functions_Read_In = 4;
      [numberOfFunctions setIntValue:4 at:0];
      NXWriteDefault("NeXTcontour", "number_Of_Functions_Read_In", "4");
    }
    if(!Two_D){
      [setDefaultNumberOfFunctions setIntValue:5 at:0];
      number_Of_Functions_Read_In = 5;
      [numberOfFunctions setIntValue:5 at:0];
      NXWriteDefault("NeXTcontour", "number_Of_Functions_Read_In", "5");
    }
    break;
  case 1:
    AeroDynamic_Functions = NO;
    [chooseDiscipline setState:1];
    NXWriteDefault("NeXTcontour", "AeroDynamics", "NO");
    number_Of_Functions_Read_In = [setDefaultNumberOfFunctions intValueAt:0];
    [numberOfFunctions setIntValue:number_Of_Functions_Read_In at:0];
    sprintf(s,"%d",number_Of_Functions_Read_In);
    NXWriteDefault("NeXTcontour", "number_Of_Functions_Read_In", s);
    break;
  }
  
  switch(s3){
  case 0:
    colorOption = YES;
    NXWriteDefault("NeXTcontour", "colorOption", "YES");
    [contourLineColor selectCellAt:0:3];
    break;
  case 1:
    colorOption = NO;
    NXWriteDefault("NeXTcontour", "colorOption", "NO");
    [contourLineColor selectCellAt:0:2];
    break;
  }

  switch(s4){
  case 0:
    printColorMode = NO;
    NXWriteDefault("NeXTcontour", "printColorMode", "NO");
    [printColor setState:0];
    break;
  case 1:
    printColorMode = YES;
    NXWriteDefault("NeXTcontour", "printColorMode", "YES");
    [printColor setState:1];
    break;
  }

  switch(s5){
  case 0:
    Binary_Data_Type = YES;
    NXWriteDefault("NeXTcontour", "Binary_Data", "YES");
    [chooseDataType setState:0];
    break;
  case 1:
    Binary_Data_Type = NO;
    NXWriteDefault("NeXTcontour", "Binary_Data", "NO");
    [chooseDataType setState:1];
    break;
  }
  
  [printColor display];
  [choose2D3DData display];
  [choose2D3DGrid display];
  [chooseDataType display];
  [chooseDiscipline display];
  [contourLineColor display];

  return self;
}

- validRequestorForSendType:(NXAtom)sendType andReturnType:(NXAtom)returnType
{
  NXAtom a;
  a = NXUniqueString(NXAsciiPboardType);
  return (a==sendType)? self :nil;
}

- writeSelectionToPasteboard:pboard types:(NXAtom *)types
{
  int i;
  NXStream *my_stream;
  int length, max_length;
  char *data;

  my_stream = NXOpenMemory(NULL,0,NX_WRITEONLY);
  for (i = 0; i < xyData.jmax; i++){
    NXPrintf(my_stream,"%g %g \n", xyData.x[i], xyData.f[i]);
  }

  NXGetMemoryBuffer(my_stream, &data, &length, &max_length);

  [pboard declareTypes:&NXAsciiPboardType num:1 owner:self];
  [pboard writeType:NXAsciiPboardType data:data length:length];

  NXCloseMemory(my_stream, NX_TRUNCATEBUFFER);
  return self;
}

- (const char *)provideMainTitle   { return [mainTitle stringValueAt:0]; }
- (const char *)provideFunctionTitle{ return [functionTitle stringValueAt:0];}

- (float)provideGridLineThickness { return [gridLineThickness floatValue]; }
- (float)provideContourLineThickness{return [contourLineThickness floatValue];}
- (NXCoord *)provideContourLevels:sender {  return contourLevels; }

- (NXColor) provideGridLineColor
{ 
  if ((NXDrawingStatus == NX_PRINTING  && [printColor state] == 0) 
      || ([printPreviewMode state] != 0 && [printColor state] == 0)){
    if([gridLineColorMatrix selectedCol] == 0)return NX_COLORLTGRAY;
    if([gridLineColorMatrix selectedCol] == 1)return NX_COLORDKGRAY;
    if([gridLineColorMatrix selectedCol] == 2)return NX_COLORBLACK;
  }
  else{
    if(colorOption){
      return [gridLineColor color];
    }
    else {
      if([gridLineColorMatrix selectedCol] == 0)return NX_COLORLTGRAY;
      if([gridLineColorMatrix selectedCol] == 1)return NX_COLORDKGRAY;
      if([gridLineColorMatrix selectedCol] == 2)return NX_COLORBLACK;
    }
  }
  return NX_COLORBLACK;		// Never reached, put in to eliminate Compiler Warning
}

- (NXColor) provideBackGroundColor
{
  if ((NXDrawingStatus == NX_PRINTING  && [printColor state] == 0)
      || ([printPreviewMode state] != 0 && [printColor state] == 0)){
    return NX_COLORWHITE;
  }
  else{
    return [backgroundColor color];
  }
}

- (NXColor) provideForeGroundColor
{
  if (((NXDrawingStatus == NX_PRINTING  && [printColor state] == 0) 
      || ([printPreviewMode state] != 0 && [printColor state] == 0))){
    return NX_COLORBLACK;
  }
  else{
    return [foregroundColor color];
  }
}

- (int) provideContourLineColor     
{
  int i = 2;
  if ((NXDrawingStatus == NX_PRINTING  && [printColor state] == 0) 
      || ([printPreviewMode state] != 0 && [printColor state] == 0)){
    return i;
  }
  else{
    if(!colorOption && [contourLineColor selectedCol]==3){
      NXBeep();	beepError = 25;	/* audible alert */
      [contourLineColor selectCellAt:0:2];
    }
    return [contourLineColor selectedCol]; 
  }
}

- (int) provideContourNumber:sender { return contourNumber;}
- (int) provideViewingChoice:sender 
                   {return [viewingTransformations selectedRow] + 4*
		      [viewingTransformations selectedCol]; }
- (int) provideViewPoint:sender 
                   {return [viewPoint state]; }
- (int) provideFunctionChoice:sender
                   { return [functionMatrix selectedRow];}

- (function_part)provideFunction:sender { return functionH; }
- (grid_part)    provideGrid:sender     { return gridH; }


- (NXCoord)provideFsmach { return solnhunk.fsmach; }
- (NXCoord)provideAlpha  { return solnhunk.alpha; }
- (NXCoord)provideRe     { return solnhunk.re; }
- (NXCoord)provideTime   { return solnhunk.time; }

- (NXCoord)provideContourmin  {return [contourLimits floatValueAt:0];}
- (NXCoord)provideContourmax  {return [contourLimits floatValueAt:1];}
- (NXCoord)provideContourinc  {return [contourLimits floatValueAt:2];}
- (NXCoord)provideFmin  {return [fMin floatValueAt:0];}
- (NXCoord)provideFmax  {return [fMax floatValueAt:0];}
- (NXCoord)provideXmin  {return [xyLimits floatValueAt:0];}
- (NXCoord)provideXmax  {return [xyLimits floatValueAt:1];}
- (NXCoord)provideYmin  {return [xyLimits floatValueAt:2];}
- (NXCoord)provideYmax  {return [xyLimits floatValueAt:3];}

- (BOOL) doAnimateF
{  if ( [animate3DFOnOff state] ) return YES;  else return NO; }
- (BOOL) doAnimateG
{  if ( [animate3DGOnOff state] ) return YES;  else return NO; }

- (BOOL) doSetAspectRatio
{  if ( [setAspectRatio state] ) return NO;  else return YES; }

- (BOOL) do2D3D 
{  if ( [choose2D3DData state] ) return YES;  else return NO; }
- (BOOL) do2D3D_grid 
{  if ( [choose2D3DGrid state] ) return YES;  else return NO; }

- (BOOL) doAeroDynamics 
{  if ( [chooseDiscipline state] ) return NO;  else return YES; }


- (BOOL) shouldChangeTitleFont
{  if ( [changeTitleFont state] ) return YES;   else return NO; }

- (BOOL) shouldChangeLabelFont
{  if ( [changeLabelFont state] ) return YES;   else return NO; }

- (BOOL) shouldShowXYLabels
{  if ( [xyLabelsOn state] ) return YES;   else return NO; }

- (BOOL) shouldShowUnitsLabel
{  if ( [unitsLabelOn state] ) return YES;   else return NO; }

- (BOOL) shouldShowContourValues
{  if ( [contourValuesOn state] ) return YES;   else return NO; }

- (BOOL) doZoom
{  if ( [zoomOnOff state] ) return YES;  else return NO; }

- (BOOL) doDrawFunction
{  if ( [drawFunction state] ) return YES;   else return NO; }

- (BOOL) doDrawGrid
{  if ( [drawGrid state] ) return YES;   else return NO; }

- (BOOL) doClearPlot
{  if ( [clearPlot state] ) return NO;   else return YES; }

- (BOOL) doSolidLines
{  if ( [solidContourLines state] ) return NO;   else return YES; }


- resetCmin:(NXCoord)aNum { [contourLimits setFloatValue:aNum at:0]; 
			    return self; }
- resetCmax:(NXCoord)aNum { [contourLimits setFloatValue:aNum at:1]; 
			    return self; }
- resetCinc:(NXCoord)aNum { [contourLimits setFloatValue:aNum at:2]; 
			    return self; }
- resetFmin:(NXCoord)aNum { [fMin setFloatValue:aNum at:0]; return self; }
- resetFmax:(NXCoord)aNum { [fMax setFloatValue:aNum at:0]; return self; }
- resetXmin:(NXCoord)aNum { [xyLimits setFloatValue:aNum at:0]; return self; }
- resetXmax:(NXCoord)aNum { [xyLimits setFloatValue:aNum at:1]; return self; }
- resetYmin:(NXCoord)aNum { [xyLimits setFloatValue:aNum at:2]; return self; }
- resetYmax:(NXCoord)aNum { [xyLimits setFloatValue:aNum at:3]; return self; }

-resetMinMax:sender
{
  if([self doDrawGrid] && ![self doDrawFunction]){
    if(gridhunk.jmax != 0) [self loadGrid:self];
    [self findGridMinAndMax];
    [self resetGridMinMax:self];
  }
  if([self doDrawFunction]){
    [self loadFunctionGrid:self];
    [self findFunctionGridMinAndMax];
    [self resetFunctionGridMinMax:self];
  }
  return self;
}


- resetGridMinMax:sender
{
  [self resetXmin:gridH.gridmin.x];
  [self resetYmin:gridH.gridmin.y];
  [self resetXmax:gridH.gridmax.x];
  [self resetYmax:gridH.gridmax.y];
  currentMin.x = gridH.gridmin.x;
  currentMin.y = gridH.gridmin.y;
  currentMax.x = gridH.gridmax.x;
  currentMax.y = gridH.gridmax.y;
  
  return self;
}

- resetFunctionGridMinMax:sender
{
  [self resetXmin:functionH.gridmin.x];
  [self resetYmin:functionH.gridmin.y];
  [self resetXmax:functionH.gridmax.x];
  [self resetYmax:functionH.gridmax.y];
  currentMin.x = functionH.gridmin.x;
  currentMin.y = functionH.gridmin.y;
  currentMax.x = functionH.gridmax.x;
  currentMax.y = functionH.gridmax.y;
  return self;
}

- resetFunctionMinMax:sender
{
  [self resetFmin:functionH.functionmin];
  [self resetFmax:functionH.functionmax];
  return self;
}

- resetGridSubsets:sender
{
  int i = 1;

    [jGridMax setIntValue:gridhunk.jmax at:0];
    [kGridMax setIntValue:gridhunk.kmax at:0];
    [lGridMax setIntValue:gridhunk.lmax at:0];
    [jGridMin setIntValue:i at:0];
    [kGridMin setIntValue:i at:0];
    [lGridMin setIntValue:i at:0];
    [jGridInc setIntValue:i at:0];
    [kGridInc setIntValue:i at:0];
    [lGridInc setIntValue:i at:0];

    return self;
}


- resetFunctionSubsets:sender
{
  int i = 1;
    [jFunctionMax setIntValue:solnhunk.jmax at:0];
    [kFunctionMax setIntValue:solnhunk.kmax at:0];
    [lFunctionMax setIntValue:solnhunk.lmax at:0];
    [jFunctionMin setIntValue:i at:0];
    [kFunctionMin setIntValue:i at:0];
    [lFunctionMin setIntValue:i at:0];
    [jFunctionInc setIntValue:i at:0];
    [kFunctionInc setIntValue:i at:0];
    [lFunctionInc setIntValue:i at:0];
    return self;
}

- resetLineSubsets:sender
{
  int i = 1;
  int lineChoice = [chooseLineData selectedRow];
  BOOL b_2D = [self do2D3D];
  
  if(b_2D){
    if(lineChoice == 2 ){
      NXBeep();	beepError = 24;	/* audible alert */
      lineChoice = 0;
      [chooseLineData selectCellAt:lineChoice:0];
    }
  }

  switch(lineChoice){
  case 0:
    [jLineMax setIntValue:gridhunk.jmax at:0];
    [kLineMax setIntValue:i at:0];
    [lLineMax setIntValue:i at:0];
    break;
  case 1:
    [kLineMax setIntValue:gridhunk.kmax at:0];
    [jLineMax setIntValue:i at:0];
    [lLineMax setIntValue:i at:0];
    break;
  case 2:
    [lLineMax setIntValue:gridhunk.lmax at:0];
    [kLineMax setIntValue:i at:0];
    [jLineMax setIntValue:i at:0];
    break;
  }

  [jLineMin setIntValue:i at:0];
  [kLineMin setIntValue:i at:0];
  [lLineMin setIntValue:i at:0];
  [jLineInc setIntValue:i at:0];
  [kLineInc setIntValue:i at:0];
  [lLineInc setIntValue:i at:0];
  
  return self;
}

- resetAll:sender
{
  [self resetGridSubsets:self];
  [self resetFunctionSubsets:self];
  [self resetFunctionMinMax:self];
  stateChangeGrid = YES;
  stateChangeFunction = YES;
  return self;
}

- resetProjectionData:sender{  
  stateChangeGrid = YES;  
  stateChangeFunction = YES;  
  return self;
}

- resetGridLineColorWell:sender{  
  if([gridLineColorMatrix selectedCol] == 0)
    [gridLineColor   setColor:NX_COLORLTGRAY];
  if([gridLineColorMatrix selectedCol] == 1)
    [gridLineColor   setColor:NX_COLORDKGRAY];
  if([gridLineColorMatrix selectedCol] == 2)
    [gridLineColor   setColor:NX_COLORBLACK];
  [gridLineColor display];
  return self;
}

- resetGridData:sender{  
  [self resetGridSubsets:self];
  stateChangeGrid = YES;  
  return self;
}

- resetLineData:sender{  
  [self resetLineSubsets:self];
  return self;
}

- resetFunctionData:sender{  
  [self resetFunctionSubsets:self];
  stateChangeFunction = YES;  
  return self;
}

- eQuateSubsets:sender{
  BOOL b_2D_grid = [self do2D3D_grid];
  [jGridMin setIntValue:[jFunctionMin intValueAt:0] at:0];
  [jGridMax setIntValue:[jFunctionMax intValueAt:0] at:0];
  [jGridInc setIntValue:[jFunctionInc intValueAt:0] at:0];
  [kGridMin setIntValue:[kFunctionMin intValueAt:0] at:0];
  [kGridMax setIntValue:[kFunctionMax intValueAt:0] at:0];
  [kGridInc setIntValue:[kFunctionInc intValueAt:0] at:0];
  if(!b_2D_grid){
    [lGridMin setIntValue:[lFunctionMin intValueAt:0] at:0];
    [lGridMax setIntValue:[lFunctionMax intValueAt:0] at:0];
    [lGridInc setIntValue:[lFunctionInc intValueAt:0] at:0];
  }
  if(b_2D_grid){
    [lGridMin setIntValue:1 at:0];
    [lGridMax setIntValue:1 at:0];
    [lGridInc setIntValue:1 at:0];
  }
  [chooseGridPlane selectCellAt:[chooseFunctionPlane selectedRow]:0];
  return self;
}

- drawPlotButton:(int)state
{
  if (state==0) {
    [plotButton highlight:NO];	/* will display normal title */
  }
  if (state==1) {
    [plotButton highlight:YES];	/* will display alternate title */
  }
  return self;
}


- makeContourLevels:sender
{
  float fmin,fmax,finc;
  int   ncont = 0,n;

  if( ![autoContours state] ){
    
    fmin  = [fMin floatValueAt:0];
    fmax  = [fMax floatValueAt:0];
    ncont = [numberContours intValueAt:0];
    
    if(ncont == 0){
      ncont = 1;
      [numberContours setIntValue:ncont at:0];
    }

    finc = (fmax-fmin)/20.;
    if(ncont != 1)finc = (fmax - fmin)/(ncont-1);
    if(ncont == 1)finc = 0.0;

    [self resetCmin:fmin];	/* send contour level info to panel */
    [self resetCmax:fmax];
    [self resetCinc:finc];

    contourNumber = ncont;
    free(contourLevels);
    contourLevels = (NXCoord *)malloc(ncont*sizeof(float));

    for (n=0; n < ncont; n++){
      contourLevels[n] = fmin + n*finc;
    }
  }
  
  else{

    fmin = [contourLimits floatValueAt:0];
    fmax = [contourLimits floatValueAt:1];
    finc = [contourLimits floatValueAt:2];

    if(finc == 0.0 && (fmax != fmin) ){
      ncont = [numberContours intValueAt:0];
      finc = (fmax-fmin)/ncont;
      [self resetCinc:finc];
    }

    if(finc != 0)ncont = (int)(ABS(fmax - fmin)/ABS(finc));
    if(fmin + ncont*finc != fmax)ncont = ncont + 1;
    if(fmin == fmax)ncont = 1;

    contourNumber = ncont;
    free(contourLevels);
    contourLevels = (NXCoord *)malloc(ncont*sizeof(float));

    for (n=0; n < ncont; n++){
      contourLevels[n] = fmin + n*finc;
    }
    if(contourLevels[ncont-1] > fmax)contourLevels[ncont-1] = fmax;
  }
  
  return self;
}


- drawPlot:sender
{
  /* get new subsets and function for plotting */

  BOOL animateF = [self doAnimateF];
  BOOL animateG = [self doAnimateG];
  BOOL b_2D = [self do2D3D];
  int planeChoice = [chooseFunctionPlane selectedRow];
  int i, i_0 = 0, i_m = 1, i_i = 1;
  char c_xmin[20],c_xmax[20],c_ymin[20],c_ymax[20];
  float xmin,xmax,ymin,ymax;

  /* error check */
  if(animateF && ![self doDrawFunction])
    {NXBeep(); beepError = 1; return self; }
  if(animateG && ![self doDrawGrid])
    {NXBeep(); beepError = 1; return self; }

  if([self doDrawGrid] && gridH.jmax == 0)
    { NXBeep(); beepError = 2; return self; }

  if([self doDrawFunction] && functionH.jmax == 0)
    {NXBeep(); beepError = 3; return self; }

/*  Need to convert the floating point vlaues of currentMin/Max to strings
    and back to floats because: when TextFields are read the floating point 
    values in the textfield is converted from a sting to a float.  If this is 
    not done then the absolute comparison of the floating points values, (e.g.
    currentMin.x != [xyLimits floatValueAt:0] ) will fail because of conversion
    errors, causing all types of problems.  thp 1/10/92 
*/

  sprintf(c_xmin,"%g",currentMin.x);
  sprintf(c_xmax,"%g",currentMax.x);
  sprintf(c_ymin,"%g",currentMin.y);
  sprintf(c_ymax,"%g",currentMax.y);
  xmin = (float)atof(c_xmin);
  ymin = (float)atof(c_ymin);
  xmax = (float)atof(c_xmax);
  ymax = (float)atof(c_ymax);

  if ( xmin != [xyLimits floatValueAt:0] 
      || xmax != [xyLimits floatValueAt:1]
      || ymin != [xyLimits floatValueAt:2]
      || ymax != [xyLimits floatValueAt:3] ) {
    oldMin.x = currentMin.x;
    currentMin.x = [xyLimits floatValueAt:0];
    oldMax.x = currentMax.x;
    currentMax.x = [xyLimits floatValueAt:1];
    oldMin.y = currentMin.y;
    currentMin.y = [xyLimits floatValueAt:2];
    oldMax.y = currentMax.y;
    currentMax.y = [xyLimits floatValueAt:3];
  }

  if(animateF && animateG)[self eQuateSubsets:self];

  if([printPreviewMode state] !=0){   /*  if preview mode reset clearplot */
    [clearPlot setState:0];    [clearPlot display];
  }

  /* function choices always take precedence over grid choices */
  if(animateG && !animateF)planeChoice = [chooseGridPlane selectedRow];
  if(animateF)planeChoice =              [chooseFunctionPlane selectedRow]; 

  switch(planeChoice){
  case 0:
    if(animateG && !animateF){
      i_0 = [jGridMin intValueAt:0]-1;
      i_i = [jGridInc intValueAt:0];
      if(i_i <= 0){
	NXBeep(); beepError = 26; 
	i_i = 1;
	[jGridInc setIntValue:i_i at:0];
	return self; }
      i_m = [jGridMax intValueAt:0]-1;
    }
    if(animateF){
      i_0 = [jFunctionMin intValueAt:0]-1;
      i_i = [jFunctionInc intValueAt:0];
      if(i_i <= 0){
	NXBeep(); beepError = 26; 
	i_i = 1;
	[jFunctionInc setIntValue:i_i at:0];
	return self; }
      i_m = [jFunctionMax intValueAt:0]-1;
    }
    break;
  case 1:
    if(animateG && !animateF){
      i_0 = [kGridMin intValueAt:0]-1;
      i_i = [kGridInc intValueAt:0];
      if(i_i <= 0){
	NXBeep(); beepError = 26; 
	i_i = 1;
	[kGridInc setIntValue:i_i at:0];
	return self; }
      i_m = [kGridMax intValueAt:0]-1;
    }
    if(animateF){
      i_0 = [kFunctionMin intValueAt:0]-1;
      i_i = [kFunctionInc intValueAt:0];
      if(i_i <= 0){
	NXBeep(); beepError = 26; 
	i_i = 1;
	[kFunctionInc setIntValue:i_i at:0];
	return self; }
      i_m = [kFunctionMax intValueAt:0]-1;
    }
    break;
  case 2:
    if(animateG && !animateF){
      i_0 = [lGridMin intValueAt:0]-1;
      i_i = [lGridInc intValueAt:0];
      if(i_i <= 0){
	NXBeep(); beepError = 26; 
	i_i = 1;
	[lGridInc setIntValue:i_i at:0];
	return self; }
      i_m = [lGridMax intValueAt:0]-1;
    }
    if(animateF){
      i_0 = [lFunctionMin intValueAt:0]-1;
      i_i = [lFunctionInc intValueAt:0];
      if(i_i <= 0){
	NXBeep(); beepError = 26; 
	i_i = 1;
	[lFunctionInc setIntValue:i_i at:0];
	return self; }
      i_m = [lFunctionMax intValueAt:0]-1;
    }
    break;
  }

  if(b_2D || (!animateF && !animateG)){    i_i = 1;    i_m = i_0;   }


  for (i = i_0; i <= i_m; i+= i_i){

    if(animateG){
      switch(planeChoice){
      case 0:
	[jGridMin setIntValue:i+1 at:0];
	break;
      case 1:
	[kGridMin setIntValue:i+1 at:0];
	break;
      case 2:
	[lGridMin setIntValue:i+1 at:0];
	break;
      }
    }
    if([self doDrawGrid])[self loadGrid:self];

    if(animateF){
      switch(planeChoice){
      case 0:
	[jFunctionMin setIntValue:i+1 at:0];
	break;
      case 1:
	[kFunctionMin setIntValue:i+1 at:0];
	break;
      case 2:
	[lFunctionMin setIntValue:i+1 at:0];
	break;
      }
    }
    if(solutionIsReadIn && [self doDrawFunction]){
      [self loadFunctionGrid:self];
      [self loadFunction:self];
      [self makeContourLevels:self];
    }
      
    if([self doDrawFunction] || [self doDrawGrid]){

      if([self checkMinMax] == 1){   /* check on min/max limits for errors */
	NXBeep(); beepError = 4; return self; }

      if(NXDrawingStatus != NX_PRINTING){
	[self drawPlotButton:1];	/* display "Plotting" */
	[canvas display];
	[self drawPlotButton:0];	/* display "Plot" */
      }
    }
    else{ NXBeep(); beepError = 22; return self; }
  }

  stateChangeGrid = NO;     /* reset stateChange so old min/max retained*/
  stateChangeFunction = NO;     /* reset stateChange so old min/max retained*/

  return self;
}


// Go through a particular datahunk and find values for datamin.x,
// datamax.x, datamin.y, datamax.y

  - findGridMinAndMax
{
  int j;

  gridH.gridmin.x = MAXFLOAT;	/* defined in /usr/include/math.h */
  gridH.gridmax.x = -MAXFLOAT;
  gridH.gridmin.y = MAXFLOAT;
  gridH.gridmax.y = -MAXFLOAT;

  for (j = 0; j < gridH.jmax*gridH.kmax; j++)  {
     gridH.gridmin.x = MIN(gridH.gridmin.x, gridH.x[j]);
     gridH.gridmax.x = MAX(gridH.gridmax.x, gridH.x[j]);
   }
  for (j = 0; j < gridH.jmax*gridH.kmax; j++)  {
     gridH.gridmin.y = MIN(gridH.gridmin.y, gridH.y[j]);
     gridH.gridmax.y = MAX(gridH.gridmax.y, gridH.y[j]);
   }
  return self;
}

  - findFunctionGridMinAndMax
{
  int j;

  functionH.gridmin.x = MAXFLOAT;	/* defined in /usr/include/math.h */
  functionH.gridmax.x = -MAXFLOAT;
  functionH.gridmin.y = MAXFLOAT;
  functionH.gridmax.y = -MAXFLOAT;

  for (j = 0; j < functionH.jmax*functionH.kmax; j++)  {
     functionH.gridmin.x = MIN(functionH.gridmin.x, functionH.x[j]);
     functionH.gridmax.x = MAX(functionH.gridmax.x, functionH.x[j]);
   }
  for (j = 0; j < functionH.jmax*functionH.kmax; j++)  {
     functionH.gridmin.y = MIN(functionH.gridmin.y, functionH.y[j]);
     functionH.gridmax.y = MAX(functionH.gridmax.y, functionH.y[j]);
   }
  return self;
}

  - findFunctionMinAndMax
{
  int j;

  functionH.functionmin = MAXFLOAT;	/* defined in /usr/include/math.h */
  functionH.functionmax = -MAXFLOAT;


  for (j = 0; j < functionH.jmax*functionH.kmax; j++)  {
     functionH.functionmin = MIN(functionH.functionmin, functionH.f[j]);
     functionH.functionmax = MAX(functionH.functionmax, functionH.f[j]);
   }
  return self;
}


// Use the OpenPanel object to get a filename
- openGrid:sender
{
//  char const  *fileTypes[2] = {"xy",0};  
  char const  *fileTypes[2] = {0,0};  
  char	fname[1024];
  
  [openPanel setTitle:"OPEN GRID FILE"];

  if ([openPanel runModalForTypes:fileTypes])  {
    strncpy(fname, [openPanel filename], 1024);
    [self openGridFile:fname];
  }
  return self;
}

// Use the OpenPanel object to get a filename
- openSolution:sender
{
//  char const  *fileTypes[2] = {"q",0};  
  char const  *fileTypes[2] = {0,0};  
  char	fname[1024];

  [openPanel setTitle:"OPEN DATA FILE"];

  if ([openPanel runModalForTypes:fileTypes])  {
    strncpy(fname, [openPanel filename], 1024);
    [self openSolnFile:fname];
  }
  return self;
}

- openGridFile:(char *)dataFile
{
    NXStream *dataStream;

    if ((dataStream = NXMapFile(dataFile, NX_READONLY)) == NULL)  {
      NXRunAlertPanel("Open", "Cannot open %s", "OK", NULL, NULL, dataFile);
      return self;
    }

    if ([self readGrid:dataStream :dataFile] == 0)  {
      NXRunAlertPanel("Read", "Couldn't read any data from %s", "OK",
		      NULL, NULL, dataFile);
      NXCloseMemory(dataStream, NX_FREEBUFFER);
      return self;
    }
    NXCloseMemory(dataStream, NX_FREEBUFFER);

    [canvasWindow setTitleAsFilename:dataFile];
    return self;
}
- openSolnFile:(char *)dataFile
{
    NXStream *dataStream;

    if ((dataStream = NXMapFile(dataFile, NX_READONLY)) == NULL)  {
      NXRunAlertPanel("Open", "Cannot open %s", "OK", NULL, NULL, dataFile);
      return self;
    }

    if ([self readSoln:dataStream :dataFile] == 0)  {
      NXRunAlertPanel("Read", "Couldn't read any data from %s", "OK",
		      NULL, NULL, dataFile);
      NXCloseMemory(dataStream, NX_FREEBUFFER);
      return self;
    }
    NXCloseMemory(dataStream, NX_FREEBUFFER);

    [canvasWindow setTitleAsFilename:dataFile];
    return self;
}



/* Allocate enough memory and read the data points */
- readGrid:(NXStream *)aDataStream :(char *)dataFile
{
  int j, numberofpoints, tmpint = 0;
  char c;
  BOOL b_2D = [self do2D3D_grid];
  int filesize,expected_filesize = 0, errorAlert = 0;
  struct stat filestat;

  /* set plot button title "Reading" */
  [plotButton setAltTitle:"Reading"];
  [plotButton highlight:YES];
  NXPing();			/* force plotButton redraw */
  
  if(![chooseDataType state]){
    NXRead(aDataStream, &gridhunk.jmax, sizeof(int));
    NXRead(aDataStream, &gridhunk.kmax, sizeof(int));
    if(!b_2D){ NXRead(aDataStream, &gridhunk.lmax, sizeof(int)); }
    else{gridhunk.lmax = 1;}
  }
  else{
    while((tmpint=NXScanf(aDataStream, "%d", &gridhunk.jmax)) == 0){
      c = (char)NXGetc(aDataStream);	/* throw away the next character */
    }
    while((tmpint=NXScanf(aDataStream, "%d", &gridhunk.kmax)) == 0){
      c = (char)NXGetc(aDataStream);	/* throw away the next character */
    }
    if(!b_2D){ 
      while((tmpint=NXScanf(aDataStream, "%d", &gridhunk.lmax)) == 0){
	c = (char)NXGetc(aDataStream);	/* throw away the next character */
      }
    }
    else{gridhunk.lmax = 1;}
  }

  numberofpoints = gridhunk.jmax*gridhunk.kmax*gridhunk.lmax;

  if(![chooseDataType state]){

  /*  check file size */
    stat(dataFile,&filestat);

    filesize = filestat.st_size;

    if(b_2D){
      
      expected_filesize = 
	2*sizeof(int) + 2*sizeof(float)*numberofpoints;

      if(filesize != expected_filesize){
	errorAlert = NXRunAlertPanel("Read Grid File", 
				     "Not a Valid 2D Grid File! %s", 
				     "Try Again?","Continue?","Abort?", 
				     dataFile);
      
	if(errorAlert  != NX_ALERTALTERNATE){
	  gridhunk.jmax = 0;
	  gridhunk.kmax = 0;
	  gridhunk.lmax = 0;
	}
	if(errorAlert  == NX_ALERTOTHER){
	  /* reset plot button */
	  [plotButton setAltTitle:"Plotting"];
	  [plotButton highlight:NO];
	  return self;
	}
	if(errorAlert  == NX_ALERTDEFAULT){
	  /* reset plot button */
	  [plotButton setAltTitle:"Plotting"];
	  [plotButton highlight:NO];
	  [self openGrid:self];
	  return self;
	}
      }
    }
    if(!b_2D){

      expected_filesize = 
	3*sizeof(int) + 3*sizeof(float)*numberofpoints;

      if(filesize != expected_filesize){
	errorAlert = NXRunAlertPanel("Read Grid File", 
				     "Not a Valid 3D Grid File! %s ", 
				     "Try Again?","Continue?","Abort?",
				     dataFile);
	if(errorAlert  != NX_ALERTALTERNATE){
	  gridhunk.jmax = 0;
	  gridhunk.kmax = 0;
	  gridhunk.lmax = 0;
	}
	if(errorAlert  == NX_ALERTOTHER){
	  /* reset plot button */
	  [plotButton setAltTitle:"Plotting"];
	  [plotButton highlight:NO];
	  return self;
	}
	if(errorAlert  == NX_ALERTDEFAULT){
	  /* reset plot button */
	  [plotButton setAltTitle:"Plotting"];
	  [plotButton highlight:NO];
	  [self openGrid:self];
	  return self;
	}
      }
    }
  }

  free((void *)gridhunk.x);
  free((void *)gridhunk.y);
  gridhunk.x = (NXCoord *)malloc(numberofpoints*sizeof(float));
  gridhunk.y = (NXCoord *)malloc(numberofpoints*sizeof(float));
  if(!b_2D){ 
    free((void *)gridhunk.z);
    gridhunk.z = (NXCoord *)malloc(numberofpoints*sizeof(float)); 
  }

  if(![chooseDataType state]){
    NXRead(aDataStream, gridhunk.x, numberofpoints*sizeof(float));
    NXRead(aDataStream, gridhunk.y, numberofpoints*sizeof(float));
    if(!b_2D){NXRead(aDataStream, gridhunk.z, numberofpoints*sizeof(float)); }
  }
  else{
    for (j=0; j<numberofpoints; j++){
      while((tmpint=NXScanf(aDataStream, "%f", &gridhunk.x[j])) == 0){
	c = (char)NXGetc(aDataStream);	/* throw away the next character */
      }
    }
    for (j=0; j<numberofpoints; j++){
      while((tmpint=NXScanf(aDataStream, "%f", &gridhunk.y[j])) == 0){
	c = (char)NXGetc(aDataStream);	/* throw away the next character */
      }
    }
    if(!b_2D){
      for (j=0; j<numberofpoints; j++){
	while((tmpint=NXScanf(aDataStream, "%f", &gridhunk.z[j])) == 0){
	  c = (char)NXGetc(aDataStream); /* throw away the next character */
	}
      }
    }
  }
  /* reset plot button */
  [plotButton setAltTitle:"Plotting"];
  [plotButton highlight:NO];

  /* initialize gridH from gridhunk */
  /* Initialize as 2D xy plane (jk plane) */
  gridH.jmax = gridhunk.jmax;
  gridH.kmax = gridhunk.kmax;
  free((void *)gridH.x);
  free((void *)gridH.y);
  gridH.x = (NXCoord *)malloc(gridH.jmax*gridH.kmax*sizeof(float));
  gridH.y = (NXCoord *)malloc(gridH.jmax*gridH.kmax*sizeof(float));

  for (j = 0; j < gridhunk.jmax*gridhunk.kmax; j++){
    gridH.x[j] = gridhunk.x[j];
    gridH.y[j] = gridhunk.y[j];
  }
      
  [self findGridMinAndMax];


  /*  On initial read function-grid min/max set to be same as grid min/max */

  gridhunk.gridmin.x = gridH.gridmin.x;
  gridhunk.gridmin.y = gridH.gridmin.y;
  gridhunk.gridmax.x = gridH.gridmax.x;
  gridhunk.gridmax.y = gridH.gridmax.y;

  /*  set min/max forms */
  [self resetGridSubsets:self];
  if(!gridIsReadIn){
    [self resetGridMinMax:self];
  }
  stateChangeGrid = NO;
  gridIsReadIn = YES;
  return self;
}

// Allocate enough memory and read the data points
- readSoln:(NXStream *)aDataStream :(char *)dataFile
{
  float gamma = 1.4;
  int j, numberofpoints,i,tmpint = 0;
  char c;
  BOOL b_2D = [self do2D3D];
  BOOL aero = [self doAeroDynamics];
  int filesize,expected_filesize = 0, errorAlert = 0;
  struct stat filestat;
  char title[14];

  /* set plot button title "Reading" */
  [plotButton setAltTitle:"Reading"];
  [plotButton highlight:YES];
  NXPing();			/* force plotButton redraw */

  number_Of_Functions_Read_In = [numberOfFunctions intValueAt:0];

  if(!aero){

    [functionMatrix setTitle:"Function 1" at:0:0];
    for(i=1; i< number_Of_Functions_Read_In; i++){
      sprintf(title,"Function %d",i+1);
      [functionMatrix setTitle:title at:i:0];
    }
    for(i=number_Of_Functions_Read_In; i<12; i++){
      [functionMatrix setTitle:"Inactive" at:i:0];
    }      
    [functionMatrix display];
  }

  if(aero){
    if(b_2D && number_Of_Functions_Read_In !=4){
      NXBeep();	beepError = 27;		/* audible alert */
      errorAlert = NXRunAlertPanel("Possible Read Data Error", 
				   "In 2D AeroDynamic Mode usually \n number of functions = 4 : you have %d", 
				   "Reset to 4","Continue?",NULL,
				   number_Of_Functions_Read_In);
      if(errorAlert  == NX_ALERTDEFAULT){
	number_Of_Functions_Read_In = 4;
	[numberOfFunctions setIntValue:4 at:0];
      }

    }
    if(!b_2D && number_Of_Functions_Read_In !=5){
      NXBeep();	beepError = 27;		/* audible alert */
      errorAlert = NXRunAlertPanel("Possible Read Data Error", 
				   "In 3D AeroDynamic Mode usually \n number of functions = 5 : you have %d", 
				   "Reset to 5","Continue?",NULL,
				   number_Of_Functions_Read_In);
      if(errorAlert  == NX_ALERTDEFAULT){
	number_Of_Functions_Read_In = 5;
	[numberOfFunctions setIntValue:5 at:0];
      }

    }

    if((b_2D && number_Of_Functions_Read_In !=4)||
       (!b_2D && number_Of_Functions_Read_In !=5)){
      [functionMatrix setTitle:"Function 1" at:0:0];
      for(i=1; i< number_Of_Functions_Read_In; i++){
	sprintf(title,"Function %d",i+1);
	[functionMatrix setTitle:title at:i:0];
      }
      for(i=number_Of_Functions_Read_In; i<12; i++){
	[functionMatrix setTitle:"Inactive" at:i:0];
      }      
    }
    else{
      [functionMatrix setTitle:"Q1: Density"    at:0:0];
      [functionMatrix setTitle:"Q2: U-Momentum" at:1:0];
      [functionMatrix setTitle:"Q3: V-Momentum" at:2:0];
      if(!b_2D)[functionMatrix setTitle:"Q4: W-Momentum" at:3:0];
      if(b_2D)[functionMatrix setTitle:"Inactive" at:3:0];
      if(!b_2D)[functionMatrix setTitle:"Q5: Energy"     at:4:0];
      if(b_2D)[functionMatrix setTitle:"Q4: Energy"     at:4:0];
      [functionMatrix setTitle:"Mach Number"    at:5:0];
      [functionMatrix setTitle:"Pressure"       at:6:0];
      [functionMatrix setTitle:"Cp"             at:7:0];
      [functionMatrix setTitle:"U-Velocity"     at:8:0];
      [functionMatrix setTitle:"V-Velocity"     at:9:0];
      if(!b_2D)[functionMatrix setTitle:"W-Velocity"     at:10:0];
      if(b_2D)[functionMatrix setTitle:"Inactive"     at:10:0];
    }
    [functionMatrix display];

  }

  if(![chooseDataType state]){
    NXRead(aDataStream, &solnhunk.jmax, sizeof(int));
    NXRead(aDataStream, &solnhunk.kmax, sizeof(int));
    if(!b_2D){ NXRead(aDataStream, &solnhunk.lmax, sizeof(int)); }
    else{solnhunk.lmax = 1;}
  }
  else{
    while((tmpint=NXScanf(aDataStream, "%d", &solnhunk.jmax)) == 0){
      c = (char)NXGetc(aDataStream);	/* throw away the next character */
    }
    while((tmpint=NXScanf(aDataStream, "%d", &solnhunk.kmax)) == 0){
      c = (char)NXGetc(aDataStream);	/* throw away the next character */
    }
    if(!b_2D){ 
      while((tmpint=NXScanf(aDataStream, "%d", &solnhunk.lmax)) == 0){
	c = (char)NXGetc(aDataStream);	/* throw away the next character */
      }
    }
    else{solnhunk.lmax = 1;}
  }

  numberofpoints = solnhunk.jmax*solnhunk.kmax*solnhunk.lmax;


  if(![chooseDataType state]){
    /*  check file size */
    stat(dataFile,&filestat);
    
    filesize = filestat.st_size;
    
    if(b_2D){
      
      if(!aero)expected_filesize = 
	2*sizeof(int) + number_Of_Functions_Read_In*sizeof(float)*
	  numberofpoints;
      
      if(aero)expected_filesize = 
	2*sizeof(int) + 4*sizeof(float) + 
	  number_Of_Functions_Read_In*sizeof(float)*numberofpoints;
      
      if(filesize != expected_filesize){
	errorAlert = NXRunAlertPanel("Read Grid File Error", 
				     "Not a Valid 2D Data File! %s", 
				     "Try Again?","Continue","Abort?",
				     dataFile);
	if(errorAlert  != NX_ALERTALTERNATE){
	  solnhunk.jmax = 0;
	  solnhunk.kmax = 0;
	  solnhunk.lmax = 0;
	}
	if(errorAlert  == NX_ALERTOTHER){
	  /* reset plot button */
	  [plotButton setAltTitle:"Plotting"];
	  [plotButton highlight:NO];
	  return self;
	}
	if(errorAlert  == NX_ALERTDEFAULT){
	  /* reset plot button */
	  [plotButton setAltTitle:"Plotting"];
	  [plotButton highlight:NO];
	  [self openSolution:self];
	  return self;
	}
      }
    }
    
    if(!b_2D){
      if(!aero)expected_filesize = 
	3*sizeof(int) + number_Of_Functions_Read_In*sizeof(float)*
	  numberofpoints;
      
      if(aero)expected_filesize = 
	3*sizeof(int) + 4*sizeof(float) + 
	  number_Of_Functions_Read_In*sizeof(float)*numberofpoints;
      
      if(filesize != expected_filesize){
	errorAlert = NXRunAlertPanel("Read Data File Error", 
				     "Not a Valid 3D Data File! %s", 
				     "Try Again?","Continue?","Abort?",
				     dataFile);
	if(errorAlert  != NX_ALERTALTERNATE){
	  solnhunk.jmax = 0;
	  solnhunk.kmax = 0;
	  solnhunk.lmax = 0;
	}
	if(errorAlert  == NX_ALERTOTHER){
	  /* reset plot button */
	  [plotButton setAltTitle:"Plotting"];
	  [plotButton highlight:NO];
	  return self;
	}
	if(errorAlert  == NX_ALERTDEFAULT){
	  /* reset plot button */
	  [plotButton setAltTitle:"Plotting"];
	  [plotButton highlight:NO];
	  [self openSolution:self];
	  return self;
	}
      }
    }
  }

  /*  checkpoint on data grid sizes against grid file*/
  if( (gridhunk.jmax != solnhunk.jmax) || (gridhunk.kmax != solnhunk.kmax)
     || (gridhunk.lmax != solnhunk.lmax) ){

    if(gridhunk.jmax == 0 ){
      errorAlert = NXRunAlertPanel("Read Data FileError", 
				   "Need to Read In A Grid First", 
				   "Try Again?","Continue?", "Abort?");
    }
    else{
      if(b_2D)errorAlert = 
	NXRunAlertPanel("Read Data FileError", 
			"Inconsistent Dimensions, you had %d %d\n File %s", 
			"Try Again?","Continue?", "Abort?",
			solnhunk.jmax,solnhunk.kmax,dataFile);
      if(!b_2D)errorAlert = 
	NXRunAlertPanel("Read Data FileError", 
			"Inconsistent Dimensions, you had %d %d %d\n File %s", 
			"Try Again?","Continue?", "Abort?",
			solnhunk.jmax,solnhunk.kmax,solnhunk.lmax,dataFile);
    }

    if(errorAlert  != NX_ALERTALTERNATE){
      solnhunk.jmax = 0;
      solnhunk.kmax = 0;
      solnhunk.lmax = 0;
    }
    if(errorAlert  == NX_ALERTOTHER){
      /* reset plot button */
      [plotButton setAltTitle:"Plotting"];
      [plotButton highlight:NO];
      return self;
    }
    if(errorAlert  == NX_ALERTDEFAULT){
      /* reset plot button */
      [plotButton setAltTitle:"Plotting"];
      [plotButton highlight:NO];
      [self openSolution:self];
      return self;
    }
  }

  if(![chooseDataType state]){
    if(aero){
      NXRead(aDataStream, &solnhunk.fsmach, sizeof(float));
      NXRead(aDataStream, &solnhunk.alpha, sizeof(float));
      NXRead(aDataStream, &solnhunk.re, sizeof(float));
      NXRead(aDataStream, &solnhunk.time, sizeof(float));
    }
  }
  else{
    if(aero){
      while((tmpint=NXScanf(aDataStream, "%f", &solnhunk.fsmach)) == 0){
	c = (char)NXGetc(aDataStream);	/* throw away the next character */
      }
      while((tmpint=NXScanf(aDataStream, "%f", &solnhunk.alpha)) == 0){
	c = (char)NXGetc(aDataStream);	/* throw away the next character */
      }
      while((tmpint=NXScanf(aDataStream, "%f", &solnhunk.re)) == 0){
	c = (char)NXGetc(aDataStream);	/* throw away the next character */
      }
      while((tmpint=NXScanf(aDataStream, "%f", &solnhunk.time)) == 0){
	c = (char)NXGetc(aDataStream);	/* throw away the next character */
      }
    }
  }
  
  free((void *)solnhunk.functions);
  solnhunk.functions    = 
    (NXCoord *)malloc(number_Of_Functions_Read_In*
		      numberofpoints*sizeof(float));

  if(aero){
    free((void *)solnhunk.pressure);
    free((void *)solnhunk.mach_number);
    solnhunk.pressure    = (NXCoord *)malloc(numberofpoints*sizeof(float));
    solnhunk.mach_number = (NXCoord *)malloc(numberofpoints*sizeof(float));
  }

  if(![chooseDataType state]){
    NXRead(aDataStream, solnhunk.functions,  
	   number_Of_Functions_Read_In*numberofpoints*sizeof(float));
  }
  else{
    for (j=0; j<numberofpoints*number_Of_Functions_Read_In; j++){
      while((tmpint=NXScanf(aDataStream, "%f", &solnhunk.functions[j])) == 0){
	c = (char)NXGetc(aDataStream);	/* throw away the next character */
      }
    }
  }

  /*compute pressure and mach number here to speed up plotting */
  if(!b_2D && aero){
    for(i=0; i < numberofpoints; i++){
      
      solnhunk.mach_number[i] = 
	 (solnhunk.functions[i+numberofpoints]*
	  solnhunk.functions[i+numberofpoints] + 
	  solnhunk.functions[i+2*numberofpoints]*
	  solnhunk.functions[i+2*numberofpoints] + 
	  solnhunk.functions[i+3*numberofpoints]*
	  solnhunk.functions[i+3*numberofpoints]); 


      solnhunk.pressure[i] = (gamma-1.0)*
	(solnhunk.functions[i+4*numberofpoints] - 
	 0.5* solnhunk.mach_number[i]/solnhunk.functions[i]);

      solnhunk.mach_number[i] = 
	sqrt(solnhunk.mach_number[i] / 
	     (gamma * solnhunk.functions[i] * solnhunk.pressure[i]));

    }
  }

  if(b_2D && aero){
    for(i=0; i < numberofpoints; i++){

      solnhunk.mach_number[i] = 
	 (solnhunk.functions[i+numberofpoints]*
	  solnhunk.functions[i+numberofpoints] + 
	  solnhunk.functions[i+2*numberofpoints]*
	  solnhunk.functions[i+2*numberofpoints]);


      solnhunk.pressure[i] = (gamma-1.0)*
	(solnhunk.functions[i+3*numberofpoints] - 
	 0.5* solnhunk.mach_number[i]/solnhunk.functions[i]);

      solnhunk.mach_number[i] = 
	sqrt(solnhunk.mach_number[i] / 
	     (gamma * solnhunk.functions[i] * solnhunk.pressure[i]));

    }
  }


    /* reset plot button */
  [plotButton setAltTitle:"Plotting"];
  [plotButton highlight:NO];

  /* initialize functionH from gridhunk */
  /* Initialize as 2D xy plane (jk plane) */
  functionH.jmax = solnhunk.jmax;
  functionH.kmax = solnhunk.kmax;

  free((void *)functionH.x);  functionH.x = 
    (NXCoord *)malloc(functionH.jmax*functionH.kmax*sizeof(float));
  free((void *)functionH.y);  functionH.y = 
    (NXCoord *)malloc(functionH.jmax*functionH.kmax*sizeof(float));
  free((void *)functionH.f);  functionH.f = 
    (NXCoord *)malloc(functionH.jmax*functionH.kmax*sizeof(float));

  for (j=0; j < solnhunk.jmax*solnhunk.kmax; j++){
    functionH.x[j] = gridhunk.x[j];
    functionH.y[j] = gridhunk.y[j];
    functionH.f[j] = solnhunk.functions[j];
  }

  if(!solutionIsReadIn){
    [self resetFunctionSubsets:self];
    [self resetLineSubsets:self];
  }

  [self findFunctionGridMinAndMax];
  [self findFunctionMinAndMax];
  if(!solutionIsReadIn){
    [self resetFunctionGridMinMax:self];
    [self resetFunctionMinMax:self];
  }
  stateChangeFunction = NO;
  solutionIsReadIn = YES;
  return self;
}



- loadGrid:sender
{
  int  j, k, l, i, ii;
  int  jdim = gridhunk.jmax;
  int  kdim = gridhunk.kmax;
  int  jmax = gridhunk.jmax;
  int  kmax = gridhunk.kmax;
  int j_0,j_i,j_m,k_0,k_i,k_m,l_0,l_i,l_m;
  int planeChoice = [chooseGridPlane selectedRow];
  int viewChoice = 
    [viewingTransformations selectedRow] + 
      4*[viewingTransformations selectedCol];
  BOOL b_2D_grid = [self do2D3D_grid];
  BOOL b_2D = [self do2D3D];

  if(!b_2D && b_2D_grid)[self eQuateSubsets:self];

  /* failsafe for 2d/3d */
  if(b_2D_grid){
    if(viewChoice != 0 && viewChoice != 4 && viewChoice != 3){
      NXBeep(); beepError = 11;
      viewChoice = 0;
      [viewingTransformations selectCellAt:viewChoice:0];
    }
    if(planeChoice != 2){
      NXBeep(); beepError = 12;
      planeChoice = 2;
      [chooseGridPlane selectCellAt:planeChoice:0];
    }
  }

  
/* shift indices down 1  */
  j_0 = [jGridMin intValueAt:0] - 1;
  j_i = [jGridInc intValueAt:0];
  j_m = [jGridMax intValueAt:0] - 1;

  k_0 = [kGridMin intValueAt:0] - 1;
  k_i = [kGridInc intValueAt:0];
  k_m = [kGridMax intValueAt:0] - 1;

  l_0 = [lGridMin intValueAt:0] - 1;
  l_i = [lGridInc intValueAt:0];
  l_m = [lGridMax intValueAt:0] - 1;
  

  /* failsafe, j or k can never be <=0 || >= max*/
  if(j_i <= 0 || j_i > gridhunk.jmax){
    NXBeep();  beepError = 20;
    j_i = 1;
    [jGridInc setIntValue:j_i at:0];
  }
  if(j_0 < 0 || j_0 > gridhunk.jmax-1){
    NXBeep();  beepError = 20;
    j_0 = 0;
    [jGridMin setIntValue:j_0+1 at:0];
  }
  if(j_m < 0 || j_m > gridhunk.jmax-1){
    NXBeep();  beepError = 20;
    j_m = gridhunk.jmax-1;
    [jGridMax setIntValue:j_m+1 at:0];
  }
  if(j_m < j_0 && planeChoice != 0){
    NXBeep();  beepError = 20;
    j_0 = 0;
    [jGridMin setIntValue:j_0+1 at:0];
    j_m = gridhunk.jmax-1;
    [jGridMax setIntValue:j_m+1 at:0];
  }
  
  if(k_i <= 0 || k_i > gridhunk.kmax){
    NXBeep();  beepError = 20;
    k_i = 1;
    [kGridInc setIntValue:k_i at:0];
  }
  if(k_0 < 0 || k_0 > gridhunk.kmax-1){
    NXBeep();  beepError = 20;
    k_0 = 0;
    [kGridMin setIntValue:k_0+1 at:0];
  }
  if(k_m < 0 || k_m > gridhunk.kmax-1){
    NXBeep();  beepError = 20;
    k_m = gridhunk.kmax-1;
    [kGridMax setIntValue:k_m+1 at:0];
  }
  if(k_m < k_0 && planeChoice != 1){
    NXBeep();  beepError = 20;
    k_0 = 0;
    [kGridMin setIntValue:k_0+1 at:0];
    k_m = gridhunk.kmax-1;
    [kGridMax setIntValue:k_m+1 at:0];
  }
  
  if(l_i <= 0 || l_i > gridhunk.lmax){
    NXBeep();  beepError = 20;
    l_i = 1;
    [lGridInc setIntValue:l_i at:0];
  }
  if(l_0 < 0 || l_0 > gridhunk.lmax-1){
    NXBeep();  beepError = 20;
    l_0 = 0;
    [lGridMin setIntValue:l_0+1 at:0];
  }
  if(l_m < 0 || l_m > gridhunk.lmax-1){
    NXBeep();  beepError = 20;
    l_m = gridhunk.lmax-1;
    [lGridMax setIntValue:l_m+1 at:0];
  }
  if(l_m < l_0 && planeChoice != 2){
    NXBeep();  beepError = 20;
    l_0 = 0;
    [lGridMin setIntValue:l_0+1 at:0];
    l_m = gridhunk.lmax-1;
    [lGridMax setIntValue:l_m+1 at:0];
  }


  switch(planeChoice){

  case 0:
    jdim = (k_m - k_0)/k_i + 1;
    kdim = (l_m - l_0)/l_i + 1;
    j_m = j_0;
    [jGridMax setIntValue:j_m+1 at:0];
    j_i = 1;
    [jGridInc setIntValue:j_i at:0];
    break;
  case 1:
    jdim = (j_m - j_0)/j_i + 1;
    kdim = (l_m - l_0)/l_i + 1;
    k_m = k_0;
    [kGridMax setIntValue:k_m+1 at:0];
    k_i = 1;
    [kGridInc setIntValue:k_i at:0];
    break;
  case 2:
    jdim = (j_m - j_0)/j_i + 1;
    kdim = (k_m - k_0)/k_i + 1;
    l_m = l_0;
    [lGridMax setIntValue:l_m+1 at:0];
    l_i = 1;
    [lGridInc setIntValue:l_i at:0];
    break;
  }

  free((void *)gridH.x);
  free((void *)gridH.y);
  
  gridH.jmax = jdim;
  gridH.kmax = kdim;
  gridH.x = (NXCoord *)malloc(jdim*kdim*sizeof(float));
  gridH.y = (NXCoord *)malloc(jdim*kdim*sizeof(float));
  
  switch(viewChoice){
    
  case 0:
    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  i = l*jmax*kmax + k*jmax + j;
	  gridH.x[ii] = gridhunk.x[i];
	  gridH.y[ii] = gridhunk.y[i];
	  ii = ii+1;
	}
      }
    }
    break;
    
  case 1:
    
    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  i = l*jmax*kmax + k*jmax + j;
	  gridH.x[ii] = gridhunk.x[i];
	  gridH.y[ii] = gridhunk.z[i];
	  ii = ii+1;
	}
      }
    }
    break;
    
  case 2:
    
    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  i = l*jmax*kmax + k*jmax + j;
	  gridH.x[ii] = gridhunk.y[i];
	  gridH.y[ii] = gridhunk.z[i];
	  ii = ii+1;
	}
      }
    }
    break;
    
  case 3:
    
    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  switch(planeChoice){
	  case 2:
	    gridH.x[ii] = (float)j+1;
	    gridH.y[ii] = (float)k+1;
	    break;
	  case 0:
	    gridH.x[ii] = (float)k+1;
	    gridH.y[ii] = (float)l+1;
	    break;
	  case 1:
	    gridH.x[ii] = (float)j+1;
	    gridH.y[ii] = (float)l+1;
	    break;
	  }
	  ii = ii+1;
	}
      }
    }
    break;
    
  case 4:
    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  i = l*jmax*kmax + k*jmax + j;
	  gridH.x[ii] = gridhunk.y[i];
	  gridH.y[ii] = gridhunk.x[i];
	  ii = ii+1;
	}
      }
    }
    break;
    
  case 5:
    
    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  i = l*jmax*kmax + k*jmax + j;
	  gridH.x[ii] = gridhunk.z[i];
	  gridH.y[ii] = gridhunk.x[i];
	  ii = ii+1;
	}
      }
    }
    break;
    
  case 6:
    
    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  i = l*jmax*kmax + k*jmax + j;
	  gridH.x[ii] = gridhunk.z[i];
	  gridH.y[ii] = gridhunk.y[i];
	  ii = ii+1;
	}
      }
    }
    break;
  }
  
  [self findGridMinAndMax];
///////  if(stateChangeGrid && !stateChangeFunction)[self resetGridMinMax:self];
  
  return self;
}

- loadFunction:sender
{
  int  j, k, l, i, ii;
  int  jdim = solnhunk.jmax;
  int  kdim = solnhunk.kmax;
  int  jmax = solnhunk.jmax;
  int  kmax = solnhunk.kmax;
  int j_0,j_i,j_m,k_0,k_i,k_m,l_0,l_i,l_m;
  int planeChoice = [chooseFunctionPlane selectedRow];
  int viewChoice = 
    [viewingTransformations selectedRow] + 
      4*[viewingTransformations selectedCol];
  int functionChoice = [functionMatrix selectedRow];
  BOOL b_2D = [self do2D3D];
  BOOL aero = [self doAeroDynamics];
  float gamma = 1.4;
  int numberofpoints;
  
  numberofpoints = solnhunk.jmax*solnhunk.kmax*solnhunk.lmax;

  /* failsafes for 2d/3d multiple vrs single functions*/

  if(!aero && functionChoice+1 > number_Of_Functions_Read_In ){
    NXBeep();	beepError = 13;		/* audible alert */
    functionChoice = 0;
    [functionMatrix selectCellAt:functionChoice:0];
  }

  if(aero){
    if((number_Of_Functions_Read_In != 4 && b_2D) ||
       (number_Of_Functions_Read_In != 5 && !b_2D)){
      if(functionChoice+1 > number_Of_Functions_Read_In ){
	NXBeep();	beepError = 13;		/* audible alert */
	functionChoice = 0;
	[functionMatrix selectCellAt:functionChoice:0];
      }
    }
  }

  if(b_2D){
    if((functionChoice == 3 || functionChoice == 10 )
       && (aero && number_Of_Functions_Read_In == 4)){
      NXBeep();	beepError = 14;	/* audible alert */
      functionChoice = 0;
      [functionMatrix selectCellAt:functionChoice:0];
    }
    if(viewChoice != 0 && viewChoice != 4 && viewChoice != 3){
      NXBeep();  beepError = 15;
      viewChoice = 0;
      [viewingTransformations selectCellAt:viewChoice:0];
    }
    if(planeChoice != 2){
      NXBeep(); beepError = 16;
      planeChoice = 2;
      [chooseFunctionPlane selectCellAt:planeChoice:0];
    }
  }


  /* shift indices down 1  */
  j_0 = [jFunctionMin intValueAt:0] - 1;
  j_i = [jFunctionInc intValueAt:0];
  j_m = [jFunctionMax intValueAt:0] - 1;

  k_0 = [kFunctionMin intValueAt:0] - 1;
  k_i = [kFunctionInc intValueAt:0];
  k_m = [kFunctionMax intValueAt:0] - 1;

  l_0 = [lFunctionMin intValueAt:0] - 1;
  l_i = [lFunctionInc intValueAt:0];
  l_m = [lFunctionMax intValueAt:0] - 1;
  

  /* failsafe, j or k can never be <=0 || >= max*/
      if(j_i <= 0 || j_i > solnhunk.jmax){
	NXBeep();  beepError = 21;
	j_i = 1;
	[jFunctionInc setIntValue:j_i at:0];
      }
      if(j_0 < 0 || j_0 > solnhunk.jmax-1){
	NXBeep();  beepError = 21;
	j_0 = 0;
	[jFunctionMin setIntValue:j_0+1 at:0];
      }
      if(j_m < 0 || j_m > solnhunk.jmax-1){
	NXBeep();  beepError = 21;
	j_m = solnhunk.jmax-1;
	[jFunctionMax setIntValue:j_m+1 at:0];
      }
      if(j_m < j_0 && planeChoice != 0){
	NXBeep();  beepError = 21;
	j_0 = 0;
	[jFunctionMin setIntValue:j_0+1 at:0];
	j_m = solnhunk.jmax-1;
	[jFunctionMax setIntValue:j_m+1 at:0];
      }

      if(k_i <= 0 || k_i > solnhunk.kmax){
	NXBeep();  beepError = 21;
	k_i = 1;
	[kFunctionInc setIntValue:k_i at:0];
      }
      if(k_0 < 0 || k_0 > solnhunk.kmax-1){
	NXBeep();  beepError = 21;
	k_0 = 0;
	[kFunctionMin setIntValue:k_0+1 at:0];
      }
      if(k_m < 0 || k_m > solnhunk.kmax-1){
	NXBeep();  beepError = 21;
	k_m = solnhunk.kmax-1;
	[kFunctionMax setIntValue:k_m+1 at:0];
      }
      if(k_m < k_0 && planeChoice != 1){
	NXBeep();  beepError = 21;
	k_0 = 0;
	[kFunctionMin setIntValue:k_0+1 at:0];
	k_m = solnhunk.kmax-1;
	[kFunctionMax setIntValue:k_m+1 at:0];
      }

      if(l_i <= 0 || l_i > solnhunk.lmax){
	NXBeep();  beepError = 21;
	l_i = 1;
	[lFunctionInc setIntValue:l_i at:0];
      }
      if(l_0 < 0 || l_0 > solnhunk.lmax-1){
	NXBeep();  beepError = 21;
	l_0 = 0;
	[lFunctionMin setIntValue:l_0+1 at:0];
      }
      if(l_m < 0 || l_m > solnhunk.lmax-1){
	NXBeep();  beepError = 21;
	l_m = solnhunk.lmax-1;
	[lFunctionMax setIntValue:l_m+1 at:0];
      }
      if(l_m < l_0 && planeChoice != 2){
	NXBeep();  beepError = 21;
	l_0 = 0;
	[lFunctionMin setIntValue:l_0+1 at:0];
	l_m = solnhunk.lmax-1;
	[lFunctionMax setIntValue:l_m+1 at:0];
      }
  
  switch(planeChoice){
    
  case 0:
    jdim = (k_m - k_0)/k_i + 1;
    kdim = (l_m - l_0)/l_i + 1;
    j_m = j_0;
    [jFunctionMax setIntValue:j_m+1 at:0];
    j_i = 1;
    [jFunctionInc setIntValue:j_i at:0];
    break;
  case 1:
    jdim = (j_m - j_0)/j_i + 1;
    kdim = (l_m - l_0)/l_i + 1;
    k_m = k_0;
    [kFunctionMax setIntValue:k_m+1 at:0];
    k_i = 1;
    [kFunctionInc setIntValue:k_i at:0];
    break;
  case 2:
    jdim = (j_m - j_0)/j_i + 1;
    kdim = (k_m - k_0)/k_i + 1;
    l_m = l_0;
    [lFunctionMax setIntValue:l_m+1 at:0];
    l_i = 1;
    [lFunctionInc setIntValue:l_i at:0];
    break;
  }

  free((void *)functionH.f);

  functionH.jmax = jdim;
  functionH.kmax = kdim;
  functionH.f =  (NXCoord *)malloc(jdim*kdim*sizeof(float));


  /* load up subset function for plotting */
  
  if(aero){
    if((number_Of_Functions_Read_In == 4 && b_2D) ||
       (number_Of_Functions_Read_In == 5 && !b_2D)){
      ii = 0;
      for (l = l_0; l <= l_m; l= l + l_i){
	for (k = k_0; k <= k_m; k= k + k_i){
	  for (j = j_0; j <= j_m; j = j + j_i){
	    i = l*jmax*kmax + k*jmax + j;
	    
	    switch(functionChoice){
	    case 0:                                  /* Q1: Density    */
	      functionH.f[ii] = solnhunk.functions[i];  
	      break;
	    case 1:                                  /* Q2: U Momentum */
	      functionH.f[ii] = solnhunk.functions[i+numberofpoints];
	      break;
	    case 2:                                  /* Q3: V Momentum */
	      functionH.f[ii] = solnhunk.functions[i+2*numberofpoints];
	      break;
	    case 3:                                  /* Q4: W Momentum */
	      functionH.f[ii] = solnhunk.functions[i+3*numberofpoints];
	      break;
	    case 4:                                  /* Q5: Energy     */
	      if(!b_2D)functionH.f[ii] = 
		solnhunk.functions[i+4*numberofpoints];
	      if(b_2D)functionH.f[ii] = solnhunk.functions[i+3*numberofpoints];
	      break;
	    case 5:                                  /* Mach Number    */
	      functionH.f[ii] = solnhunk.mach_number[i];
	      break;
	    case 6:                                  /* Pressure       */
	      functionH.f[ii] = solnhunk.pressure[i];
	      break;
	    case 7:
	      functionH.f[ii] =                      /* Cp             */
		2.0/(gamma*solnhunk.fsmach*solnhunk.fsmach) * 
		  (solnhunk.pressure[i]*gamma - 1.);
	      break;
	    case 8:                                  /* U Velocity     */
	      functionH.f[ii] = 
		solnhunk.functions[i+numberofpoints]/solnhunk.functions[i];
	      break;
	    case 9:                                  /* V Velocity     */
	      functionH.f[ii] = 
		solnhunk.functions[i+2*numberofpoints]/solnhunk.functions[i];
	      break;
	    case 10:                                 /* W Velocity     */
	      functionH.f[ii] = 
		solnhunk.functions[i+3*numberofpoints]/solnhunk.functions[i];
	      break;
	    }
	    ii = ii+1;
	  }
	}
      }
    }
    else{
      ii = 0;
      for (l = l_0; l <= l_m; l= l + l_i){
	for (k = k_0; k <= k_m; k= k + k_i){
	  for (j = j_0; j <= j_m; j = j + j_i){
	    i = l*jmax*kmax + k*jmax + j;
	    functionH.f[ii] = 
	      solnhunk.functions[i + functionChoice*numberofpoints];
	    ii = ii+1;
	  }
	}
      }
    }
  }
  
  if(!aero){
    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  i = l*jmax*kmax + k*jmax + j;
	  functionH.f[ii] = 
	    solnhunk.functions[i + functionChoice*numberofpoints];
	  ii = ii+1;
	}
      }
    }
  }
  
  
  [self findFunctionMinAndMax];
  [self resetFunctionMinMax:self];  

  return self;
}

- loadFunctionGrid:sender
{
  int  j, k, l, i, ii;
  BOOL b_2D = [self do2D3D];
  BOOL b_2D_grid = [self do2D3D_grid];
  int jdim,kdim,jmax,kmax,planeChoice;
  int j_0,j_i,j_m,k_0,k_i,k_m,l_0,l_i,l_m;
  int viewChoice = 
    [viewingTransformations selectedRow] + 
      4*[viewingTransformations selectedCol];

  if(b_2D == b_2D_grid){
    jdim = solnhunk.jmax;
    kdim = solnhunk.kmax;
    jmax = solnhunk.jmax;
    kmax = solnhunk.kmax;
    planeChoice = [chooseFunctionPlane selectedRow];}
  else{
    jdim = gridhunk.jmax;
    kdim = gridhunk.kmax;
    jmax = gridhunk.jmax;
    kmax = gridhunk.kmax;
    planeChoice = [chooseGridPlane selectedRow];}

  /* failsafe for 2d/3d */
  if(b_2D_grid){
    if(viewChoice != 0 && viewChoice != 4 && viewChoice != 3){
      NXBeep(); beepError = 18;
      viewChoice = 0;
      [viewingTransformations selectCellAt:viewChoice:0];
    }
    if(planeChoice != 2){
      NXBeep();  beepError = 19;
      planeChoice = 2;
      if(b_2D == b_2D_grid)[chooseFunctionPlane selectCellAt:planeChoice:0];
      if(b_2D != b_2D_grid)[chooseGridPlane selectCellAt:planeChoice:0];
    }
  }


  /* shift indices down 1  */
  if(b_2D == b_2D_grid){
    j_0 = [jFunctionMin intValueAt:0] - 1;
    j_i = [jFunctionInc intValueAt:0];
    j_m = [jFunctionMax intValueAt:0] - 1;

    k_0 = [kFunctionMin intValueAt:0] - 1;
    k_i = [kFunctionInc intValueAt:0];
    k_m = [kFunctionMax intValueAt:0] - 1;

    l_0 = [lFunctionMin intValueAt:0] - 1;
    l_i = [lFunctionInc intValueAt:0];
    l_m = [lFunctionMax intValueAt:0] - 1;

  /* failsafe, j or k can never be <=0 || >= max*/
    if(j_i <= 0 || j_i > solnhunk.jmax){
      NXBeep();  beepError = 21;
      j_i = 1;
      [jFunctionInc setIntValue:j_i at:0];
    }
    if(j_0 < 0 || j_0 > solnhunk.jmax-1){
      NXBeep();  beepError = 21;
      j_0 = 0;
      [jFunctionMin setIntValue:j_0+1 at:0];
    }
    if(j_m < 0 || j_m > solnhunk.jmax-1){
      NXBeep();  beepError = 21;
      j_m = solnhunk.jmax-1;
      [jFunctionMax setIntValue:j_m+1 at:0];
    }
    if(j_m < j_0 && planeChoice != 0){
      NXBeep();  beepError = 21;
      j_0 = 0;
      [jFunctionMin setIntValue:j_0+1 at:0];
      j_m = solnhunk.jmax-1;
      [jFunctionMax setIntValue:j_m+1 at:0];
    }
    
    if(k_i <= 0 || k_i > solnhunk.kmax){
      NXBeep();  beepError = 21;
      k_i = 1;
      [kFunctionInc setIntValue:k_i at:0];
    }
    if(k_0 < 0 || k_0 > solnhunk.kmax-1){
      NXBeep();  beepError = 21;
      k_0 = 0;
      [kFunctionMin setIntValue:k_0+1 at:0];
    }
    if(k_m < 0 || k_m > solnhunk.kmax-1){
      NXBeep();  beepError = 21;
      k_m = solnhunk.kmax-1;
      [kFunctionMax setIntValue:k_m+1 at:0];
    }
    if(k_m < k_0 && planeChoice != 1){
      NXBeep();  beepError = 21;
      k_0 = 0;
      [kFunctionMin setIntValue:k_0+1 at:0];
      k_m = solnhunk.kmax-1;
      [kFunctionMax setIntValue:k_m+1 at:0];
    }
    
    if(l_i <= 0 || l_i > solnhunk.lmax){
      NXBeep();  beepError = 21;
      l_i = 1;
      [lFunctionInc setIntValue:l_i at:0];
    }
    if(l_0 < 0 || l_0 > solnhunk.lmax-1){
      NXBeep();  beepError = 21;
      l_0 = 0;
      [lFunctionMin setIntValue:l_0+1 at:0];
    }
    if(l_m < 0 || l_m > solnhunk.lmax-1){
      NXBeep();  beepError = 21;
      l_m = solnhunk.lmax-1;
      [lFunctionMax setIntValue:l_m+1 at:0];
    }
    if(l_m < l_0 && planeChoice != 2){
      NXBeep();  beepError = 21;
      l_0 = 0;
      [lFunctionMin setIntValue:l_0+1 at:0];
      l_m = solnhunk.lmax-1;
    [lFunctionMax setIntValue:l_m+1 at:0];
    }
  
  }
  else{
    j_0 = [jGridMin intValueAt:0] - 1;
    j_i = [jGridInc intValueAt:0];
    j_m = [jGridMax intValueAt:0] - 1;

    k_0 = [kGridMin intValueAt:0] - 1;
    k_i = [kGridInc intValueAt:0];
    k_m = [kGridMax intValueAt:0] - 1;

    l_0 = [lGridMin intValueAt:0] - 1;
    l_i = [lGridInc intValueAt:0];
    l_m = [lGridMax intValueAt:0] - 1;

  /* failsafe, j or k can never be <=0 || >= max*/
    if(j_i <= 0 || j_i > solnhunk.jmax){
      NXBeep();  beepError = 21;
      j_i = 1;
      [jGridInc setIntValue:j_i at:0];
    }
    if(j_0 < 0 || j_0 > solnhunk.jmax-1){
      NXBeep();  beepError = 21;
      j_0 = 0;
      [jGridMin setIntValue:j_0+1 at:0];
    }
    if(j_m < 0 || j_m > solnhunk.jmax-1){
      NXBeep();  beepError = 21;
      j_m = solnhunk.jmax-1;
      [jGridMax setIntValue:j_m+1 at:0];
    }
    if(j_m < j_0 && planeChoice != 0){
      NXBeep();  beepError = 21;
      j_0 = 0;
      [jGridMin setIntValue:j_0+1 at:0];
      j_m = solnhunk.jmax-1;
      [jGridMax setIntValue:j_m+1 at:0];
    }
    
    if(k_i <= 0 || k_i > solnhunk.kmax){
      NXBeep();  beepError = 21;
      k_i = 1;
      [kGridInc setIntValue:k_i at:0];
    }
    if(k_0 < 0 || k_0 > solnhunk.kmax-1){
      NXBeep();  beepError = 21;
      k_0 = 0;
      [kGridMin setIntValue:k_0+1 at:0];
    }
    if(k_m < 0 || k_m > solnhunk.kmax-1){
      NXBeep();  beepError = 21;
      k_m = solnhunk.kmax-1;
      [kGridMax setIntValue:k_m+1 at:0];
    }
    if(k_m < k_0 && planeChoice != 1){
      NXBeep();  beepError = 21;
      k_0 = 0;
      [kGridMin setIntValue:k_0+1 at:0];
      k_m = solnhunk.kmax-1;
      [kGridMax setIntValue:k_m+1 at:0];
    }
    
    if(l_i <= 0 || l_i > solnhunk.lmax){
      NXBeep();  beepError = 21;
      l_i = 1;
      [lGridInc setIntValue:l_i at:0];
    }
    if(l_0 < 0 || l_0 > solnhunk.lmax-1){
      NXBeep();  beepError = 21;
      l_0 = 0;
      [lGridMin setIntValue:l_0+1 at:0];
    }
    if(l_m < 0 || l_m > solnhunk.lmax-1){
      NXBeep();  beepError = 21;
      l_m = solnhunk.lmax-1;
      [lGridMax setIntValue:l_m+1 at:0];
    }
    if(l_m < l_0 && planeChoice != 2){
      NXBeep();  beepError = 21;
      l_0 = 0;
      [lGridMin setIntValue:l_0+1 at:0];
      l_m = solnhunk.lmax-1;
    [lGridMax setIntValue:l_m+1 at:0];
    }
  
  }

  switch(planeChoice){

  case 0:
    jdim = (k_m - k_0)/k_i + 1;
    kdim = (l_m - l_0)/l_i + 1;
    j_m = j_0;
    [jFunctionMax setIntValue:j_m+1 at:0];
    j_i = 1;
    [jFunctionInc setIntValue:j_i at:0];
    break;
  case 1:
    jdim = (j_m - j_0)/j_i + 1;
    kdim = (l_m - l_0)/l_i + 1;
    k_m = k_0;
    [kFunctionMax setIntValue:k_m+1 at:0];
    k_i = 1;
    [kFunctionInc setIntValue:k_i at:0];
    break;
  case 2:
    jdim = (j_m - j_0)/j_i + 1;
    kdim = (k_m - k_0)/k_i + 1;
    l_m = l_0;
    [lFunctionMax setIntValue:l_m+1 at:0];
    l_i = 1;
    [lFunctionInc setIntValue:l_i at:0];
    break;
  }

  free((void *)functionH.x);
  free((void *)functionH.y);

  functionH.jmax = jdim;
  functionH.kmax = kdim;
  functionH.x =  (NXCoord *)malloc(jdim*kdim*sizeof(float));
  functionH.y =  (NXCoord *)malloc(jdim*kdim*sizeof(float));


  /* load up subset function grid for plotting */
  
  /*  load up grid */
  switch(viewChoice){

  case 0:
    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  i = l*jmax*kmax + k*jmax + j;
	  functionH.x[ii] = gridhunk.x[i];
	  functionH.y[ii] = gridhunk.y[i];
	  ii = ii+1;
	}
      }
    }
    break;

  case 1:

    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  i = l*jmax*kmax + k*jmax + j;
	  functionH.x[ii] = gridhunk.x[i];
	  functionH.y[ii] = gridhunk.z[i];
	  ii = ii+1;
	}
      }
    }
    break;

  case 2:

    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  i = l*jmax*kmax + k*jmax + j;
	  functionH.x[ii] = gridhunk.y[i];
	  functionH.y[ii] = gridhunk.z[i];
	  ii = ii+1;
	}
      }
    }
    break;

  case 3:

    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  switch(planeChoice){
	  case 2:
	    functionH.x[ii] = (float)j+1;
	    functionH.y[ii] = (float)k+1;
	    break;
	  case 0:
	    functionH.x[ii] = (float)k+1;
	    functionH.y[ii] = (float)l+1;
	    break;
	  case 1:
	    functionH.x[ii] = (float)j+1;
	    functionH.y[ii] = (float)l+1;
	    break;
	  }
	  ii = ii+1;
	}
      }
    }
    break;

  case 4:
    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  i = l*jmax*kmax + k*jmax + j;
	  functionH.x[ii] = gridhunk.y[i];
	  functionH.y[ii] = gridhunk.x[i];
	  ii = ii+1;
	}
      }
    }
    break;

  case 5:

    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  i = l*jmax*kmax + k*jmax + j;
	  functionH.x[ii] = gridhunk.z[i];
	  functionH.y[ii] = gridhunk.x[i];
	  ii = ii+1;
	}
      }
    }
    break;

  case 6:

    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  i = l*jmax*kmax + k*jmax + j;
	  functionH.x[ii] = gridhunk.z[i];
	  functionH.y[ii] = gridhunk.y[i];
	  ii = ii+1;
	}
      }
    }
    break;
  }


  [self findFunctionGridMinAndMax];
/////  if(stateChangeFunction)[self resetFunctionGridMinMax:self];
  return self;
}

- whyTheBeep:sender
{
  switch(beepError){
  case 0:
    NXRunAlertPanel("The Beep Panel", 
      "BEEP BEEP, We All Need Some Info Sometime\n Just Click Why The Beep? whenever you hear BEEP\n                A Service Of NeXTcontour",
		    "OK",NULL,NULL);
    break;
  case 1:
    NXRunAlertPanel("The Beep Happened Because", 
		    "Can't animate without drawing function",
		    "OK",NULL,NULL);
    break;
  case 2:
    NXRunAlertPanel("The Beep Happened Because", 
		    "No grid available for plotting \n read in a Grid File",
		    "OK",NULL,NULL);
    break;
  case 3:
    NXRunAlertPanel("The Beep Happened Because", 
	    "No function available for plotting \n read in a Data File",
		    "OK",NULL,NULL);
    break;
  case 4:
    NXRunAlertPanel("The Beep Happened Because", 
		    "You Can't Plot With min = max \n Check min/max Subsets, Plane and Projection",
		    "OK",NULL,NULL);
    break;
  case 11:
    NXRunAlertPanel("The Beep Happened Because", 
	    "Viewing Choice Must Be XY or YX for 2D Cases \n I Fixed It For You",
		    "OK",NULL,NULL);
    break;
  case 12:
    NXRunAlertPanel("The Beep Happened Because", 
	    "Plane Choice Must Be l for 2D Cases \n I Fixed It For You",
		    "OK",NULL,NULL);
    break;
  case 13:
    NXRunAlertPanel("The Beep Happened Because", 
   "Function Choice >  Number of Functions Available \n I Fixed It For You",
		    "OK",NULL,NULL);
    break;
  case 14:
    NXRunAlertPanel("The Beep Happened Because", 
   "For 2D Cases You Can't Plot W or W-Momentum \n I Fixed It For You",
		    "OK",NULL,NULL);
    break;
  case 15:
    NXRunAlertPanel("The Beep Happened Because", 
	    "Viewing Choice Must Be XY or YX for 2D Cases \n I Fixed It For You",
		    "OK",NULL,NULL);
    break;
  case 16:
    NXRunAlertPanel("The Beep Happened Because", 
	    "Plane Choice Must Be l for 2D Cases \n I Fixed It For You",
		    "OK",NULL,NULL);
    break;
  case 17:
    NXRunAlertPanel("The Beep Happened Because", 
   "For 2D Cases You Can't Plot W or W-Momentum \n I Fixed It For You",
		    "OK",NULL,NULL);
    break;
  case 18:
    NXRunAlertPanel("The Beep Happened Because", 
	    "Viewing Choice Must Be XY or YX for 2D Cases \n I Fixed It For You",
		    "OK",NULL,NULL);
    break;
  case 19:
    NXRunAlertPanel("The Beep Happened Because", 
	    "Plane Choice Must Be l for 2D Cases \n I Fixed It For You",
		    "OK",NULL,NULL);
    break;
  case 20:
    NXRunAlertPanel("The Beep Happened Because", 
	    "Indices Out Of Range For Grid Subsets\n I Fixed It For You",
		    "OK",NULL,NULL);
    break;
  case 21:
    NXRunAlertPanel("The Beep Happened Because", 
	    "Indices Out Of Range For Function Subsets\n I Fixed It For You",
		    "OK",NULL,NULL);
    break;
  case 22:
    NXRunAlertPanel("The Beep Happened Because", 
	    "You Need To Choose Plot Grid or Plot Function\n GO FOR IT!",
		    "OK",NULL,NULL);
    break;
  case 23:
    NXRunAlertPanel("The Beep Happened Because", 
   "For 2D Cases You Can't Plot Z Coordnate Data Line\n I Fixed It For You",
		    "OK",NULL,NULL);
    break;
  case 24:
    NXRunAlertPanel("The Beep Happened Because", 
   "For 2D Cases You Can't Plot l Coordnate Data Line\n I Fixed It For You",
		    "OK",NULL,NULL);
    break;
  case 25:
    NXRunAlertPanel("The Beep Happened Because", 
   "Color Option Not Allow By Preferences \n Reset Preferences Or Use Black/Gray \n I Reset Line Color For Now",
		    "OK",NULL,NULL);
    break;
  case 26:
    NXRunAlertPanel("The Beep Happened Because", 
   "You Can not animate with <= zero increment \n I Fixed It For You",
		    "OK",NULL,NULL);
    break;
  case 27:
    NXRunAlertPanel("The Beep Happened Because", 
   "The number of funtions to be read in was checked \n previous warning panel took care of it for you",
		    "OK",NULL,NULL);
    break;
  case 28:
    NXRunAlertPanel("The Beep Happened Because", 
   "You asked for an awful lot of list data \n The alert panel took care of it for you",
		    "OK",NULL,NULL);
    break;
  }
  return self;
}

- (int)checkMinMax
{ 
  float xmin = [xyLimits floatValueAt:0];
  float xmax = [xyLimits floatValueAt:1];
  float ymin = [xyLimits floatValueAt:2];
  float ymax = [xyLimits floatValueAt:3];
  int error = 0;

  if(xmin == xmax){
    NXRunAlertPanel
      ("Min/Max Check", 
       "Plot Error xmin = xmax : Check min/max \n Subsets, Plane Choice and Projections", 
       "OK",NULL,NULL);
    error = 1;
  }
  if(ymin == ymax){
    NXRunAlertPanel
      ("Min/Max Check", 
       "Plot Error ymin = ymax : Check min/max \n Subsets, Plane Choice and Projections", 
       "OK",NULL,NULL);
    error = 1;
  }

  return error;
}

- writeOutLineData:sender 
{
  int  jdim = solnhunk.jmax;
  int  jmax = solnhunk.jmax;
  int  kmax = solnhunk.kmax;
  int  j, k, l, i, ii, i_minus;
  int j_0,j_i,j_m,k_0,k_i,k_m,l_0,l_i,l_m;
  int coordinateChoice = [absissaCoordinate selectedRow];
  int lineChoice = [chooseLineData selectedRow];
  int functionChoice = [functionMatrix selectedRow];
  BOOL b_2D = [self do2D3D];
  BOOL aero = [self doAeroDynamics];
  float gamma = 1.4;
  float xyData_save;
  int numberofpoints = solnhunk.jmax*solnhunk.kmax*solnhunk.lmax;

  /* failsafes for 2d/3d multiple vrs single functions*/

  if(!aero && functionChoice+1 > number_Of_Functions_Read_In ){
    NXBeep();	beepError = 13;		/* audible alert */
    functionChoice = 0;
    [functionMatrix selectCellAt:functionChoice:0];
  }
  if(aero){
    if((number_Of_Functions_Read_In != 4 && b_2D) ||
       (number_Of_Functions_Read_In != 5 && !b_2D)){
      if(functionChoice+1 > number_Of_Functions_Read_In ){
	NXBeep();	beepError = 13;		/* audible alert */
	functionChoice = 0;
	[functionMatrix selectCellAt:functionChoice:0];
      }
    }
  }

  if(b_2D){
    if((functionChoice == 3 || functionChoice == 10 )
       && (aero && number_Of_Functions_Read_In == 4)){
      NXBeep();	beepError = 14;	/* audible alert */
      functionChoice = 0;
      [functionMatrix selectCellAt:functionChoice:0];
    }
    if(coordinateChoice == 2 ){
      NXBeep();	beepError = 23;	/* audible alert */
      coordinateChoice = 0;
      [absissaCoordinate selectCellAt:coordinateChoice:0];
    }
    if(lineChoice == 2 ){
      NXBeep();	beepError = 24;	/* audible alert */
      lineChoice = 0;
      [chooseLineData selectCellAt:lineChoice:0];
    }
  }


  /* shift indices down 1  */
  j_0 = [jLineMin intValueAt:0] - 1;
  j_i = [jLineInc intValueAt:0];
  j_m = [jLineMax intValueAt:0] - 1;

  k_0 = [kLineMin intValueAt:0] - 1;
  k_i = [kLineInc intValueAt:0];
  k_m = [kLineMax intValueAt:0] - 1;

  l_0 = [lLineMin intValueAt:0] - 1;
  l_i = [lLineInc intValueAt:0];
  l_m = [lLineMax intValueAt:0] - 1;
  

  /* failsafe, j or k can never be <=0 || >= max*/
  if(j_i <= 0 || j_i > solnhunk.jmax){
    NXBeep();  beepError = 21;
    j_i = 1;
    [jLineInc setIntValue:j_i at:0];
  }
  if(j_0 < 0 || j_0 > solnhunk.jmax-1){
    NXBeep();  beepError = 21;
    j_0 = 0;
    [jLineMin setIntValue:j_0+1 at:0];
  }
  if(j_m < 0 || j_m > solnhunk.jmax-1){
    NXBeep();  beepError = 21;
    j_m = solnhunk.jmax-1;
    [jLineMax setIntValue:j_m+1 at:0];
  }
  if(j_m < j_0 && lineChoice == 0){
    NXBeep();  beepError = 21;
    j_0 = 0;
    [jLineMin setIntValue:j_0+1 at:0];
    j_m = solnhunk.jmax-1;
    [jLineMax setIntValue:j_m+1 at:0];
  }

  if(k_i <= 0 || k_i > solnhunk.kmax){
    NXBeep();  beepError = 21;
    k_i = 1;
    [kLineInc setIntValue:k_i at:0];
  }
  if(k_0 < 0 || k_0 > solnhunk.kmax-1){
    NXBeep();  beepError = 21;
    k_0 = 0;
    [kLineMin setIntValue:k_0+1 at:0];
  }
  if(k_m < 0 || k_m > solnhunk.kmax-1){
    NXBeep();  beepError = 21;
    k_m = solnhunk.kmax-1;
    [kLineMax setIntValue:k_m+1 at:0];
  }
  if(k_m < k_0 && lineChoice == 1){
    NXBeep();  beepError = 21;
    k_0 = 0;
    [kLineMin setIntValue:k_0+1 at:0];
    k_m = solnhunk.kmax-1;
    [kLineMax setIntValue:k_m+1 at:0];
  }
  
  if(l_i <= 0 || l_i > solnhunk.lmax){
    NXBeep();  beepError = 21;
    l_i = 1;
    [lLineInc setIntValue:l_i at:0];
  }
  if(l_0 < 0 || l_0 > solnhunk.lmax-1){
    NXBeep();  beepError = 21;
    l_0 = 0;
    [lLineMin setIntValue:l_0+1 at:0];
  }
  if(l_m < 0 || l_m > solnhunk.lmax-1){
    NXBeep();  beepError = 21;
    l_m = solnhunk.lmax-1;
    [lLineMax setIntValue:l_m+1 at:0];
  }
  if(l_m < l_0 && lineChoice == 2){
    NXBeep();  beepError = 21;
    l_0 = 0;
    [lLineMin setIntValue:l_0+1 at:0];
    l_m = solnhunk.lmax-1;
    [lLineMax setIntValue:l_m+1 at:0];
  }


  switch(lineChoice){

  case 0:
    jdim = (j_m - j_0)/j_i + 1;
    k_m = k_0;
    l_m = l_0;
    k_i = 1;
    l_i = 1;
    [kLineMax setIntValue:k_m+1 at:0];
    [lLineMax setIntValue:l_m+1 at:0];
    [kLineInc setIntValue:k_i at:0];
    [lLineInc setIntValue:l_i at:0];
    break;
  case 1:
    jdim = (k_m - k_0)/k_i + 1;
    j_m = j_0;
    l_m = l_0;
    j_i = 1;
    l_i = 1;
    [jLineMax setIntValue:j_m+1 at:0];
    [lLineMax setIntValue:l_m+1 at:0];
    [jLineInc setIntValue:j_i at:0];
    [lLineInc setIntValue:l_i at:0];
    break;
  case 2:
    jdim = (l_m - l_0)/l_i + 1;
    k_m = k_0;
    j_m = j_0;
    k_i = 1;
    j_i = 1;
    [kLineMax setIntValue:k_m+1 at:0];
    [jLineMax setIntValue:j_m+1 at:0];
    [kLineInc setIntValue:k_i at:0];
    [jLineInc setIntValue:j_i at:0];
    break;
  }

  free((void *)xyData.f);
  free((void *)xyData.x);

  xyData.jmax = jdim;

  xyData.x =  (NXCoord *)malloc(jdim*sizeof(float));
  xyData.f =  (NXCoord *)malloc(jdim*sizeof(float));

  if(coordinateChoice == 3){
    ii = 0;
    xyData_save = 0.0;
    i_minus = l_0*jmax*kmax + k_0*jmax + j_0;
    
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  i = l*jmax*kmax + k*jmax + j;
	  if(b_2D){
	    xyData.x[ii] = xyData_save + 
	      sqrt(
		   (gridhunk.x[i]-gridhunk.x[i_minus])*
		   (gridhunk.x[i]-gridhunk.x[i_minus]) +
		   (gridhunk.y[i]-gridhunk.y[i_minus])*
		   (gridhunk.y[i]-gridhunk.y[i_minus]) );
	  }
	  if(!b_2D){
	    xyData.x[ii] = xyData_save + 
	      sqrt(
		   (gridhunk.x[i]-gridhunk.x[i_minus])*
		   (gridhunk.x[i]-gridhunk.x[i_minus]) +
		   (gridhunk.y[i]-gridhunk.y[i_minus])*
		   (gridhunk.y[i]-gridhunk.y[i_minus]) +
		   (gridhunk.z[i]-gridhunk.z[i_minus])*
		   (gridhunk.z[i]-gridhunk.z[i_minus]) );
	  }
	  i_minus = i;
	  xyData_save = xyData.x[ii];
	  ii = ii+1;
	}
      }
    }
  }

  ii = 0;
  for (l = l_0; l <= l_m; l= l + l_i){
    for (k = k_0; k <= k_m; k= k + k_i){
      for (j = j_0; j <= j_m; j = j + j_i){
	i = l*jmax*kmax + k*jmax + j;

	switch(coordinateChoice){
	case 0:
	  xyData.x[ii] = gridhunk.x[i];
	  break;
	case 1:
	  xyData.x[ii] = gridhunk.y[i];
	  break;
	case 2:
	  xyData.x[ii] = gridhunk.z[i];
	  break;
	case 3:
	  break;
	case 4:
	  if(lineChoice==0)xyData.x[ii] = j+1;
	  if(lineChoice==1)xyData.x[ii] = k+1;
	  if(lineChoice==2)xyData.x[ii] = l+1;
	  break;
	}

	if(aero){
	  switch(functionChoice){
	  case 0:
	    xyData.f[ii] = solnhunk.functions[i];
	    break;
	  case 1:
	    xyData.f[ii] = solnhunk.functions[i+numberofpoints];
	    break;
	  case 2:
	    xyData.f[ii] = solnhunk.functions[i+2*numberofpoints];
	    break;
	  case 3:
	    xyData.f[ii] = solnhunk.functions[i+3*numberofpoints];
	    break;
	  case 4:
	    if(!b_2D)xyData.f[ii] = solnhunk.functions[i+4*numberofpoints];
	    if(b_2D)xyData.f[ii] = solnhunk.functions[i+3*numberofpoints];
	    break;
	  case 5:
	    xyData.f[ii] = solnhunk.mach_number[i];
	    break;
	  case 6:
	    xyData.f[ii] = solnhunk.pressure[i];
	    break;
	  case 7:
	    xyData.f[ii] =
	      2.0/(gamma*solnhunk.fsmach*solnhunk.fsmach) * 
		(solnhunk.pressure[i]*gamma - 1.);
	    break;
	  case 8:
	    xyData.f[ii] = 
	      solnhunk.functions[i+numberofpoints]/solnhunk.functions[i];
	    break;
	  case 9:
	    xyData.f[ii] = 
	      solnhunk.functions[i+2*numberofpoints]/solnhunk.functions[i];
	    break;
	  case 10:
	    xyData.f[ii] = 
	      solnhunk.functions[i+3*numberofpoints]/solnhunk.functions[i];
	    break;
	  }
	}

	if(!aero){
	  xyData.f[ii] = 
	    solnhunk.functions[i + functionChoice*numberofpoints];
	}

	ii = ii+1;
      }
    }
  }

  return self;
}

- (BOOL)appAcceptsAnotherFile:sender
/* Added by J. Gregory 9-Oct-91. */
{
	return YES;
}

- (int)app:sender openFile:(const char *)fullPath type:(const char *)aType
{
  if(gridIsReadIn && solutionIsReadIn)
    {gridIsReadIn = NO; solutionIsReadIn = NO;}

  if(!gridIsReadIn){
    [self openGridFile:(char *)fullPath];}
  else{
    [self openSolnFile:(char *)fullPath];}
    
  return YES;
}
/*
 * This function is called by the PlotView object during zooming.
 */
- stackOldMinMax:(float)xmin :(float)xmax :(float)ymin :(float)ymax
{
  oldMin = currentMin;		/* structure assignment */
  oldMax = currentMax;
  currentMin.x = xmin;
  currentMax.x = xmax;
  currentMin.y = ymin;
  currentMax.y = ymax;
  return self;
}

- previousView:sender
{
  NXPoint tmp;

  [self resetXmin:oldMin.x];
  [self resetXmax:oldMax.x];
  [self resetYmin:oldMin.y];
  [self resetYmax:oldMax.y];
  tmp        = oldMin;
  oldMin     = currentMin;
  currentMin = tmp;
  tmp        = oldMax;
  oldMax     = currentMax;
  currentMax = tmp;
  [self drawPlotButton:1];	/* display "Plotting" */
  [canvas display];
  [self drawPlotButton:0];	/* display "Plot" */

  return self;
}

// newTextView: is invoked in response to a new empty window request. It
// creates a new window containing a TextView. Note that we want new windows 
// to be offset from each other by some amount; hence the use of Rect.

#define g_ORIGX 150.0
#define g_ORIGY 200.0
static NXRect gRect = {{g_ORIGX, g_ORIGY},{900.0,600.0}};

- listGridData:sender
{   
  char data[64];
  const char *types[1];
  int length, max_length;
  char *s_data;
  static int window_number = 0;

  id newTextView;

  NXOffsetRect(&gRect, 20.0, -20.0);
  if (gRect.origin.y < 0) {
    gRect.origin.y = g_ORIGY;
    gRect.origin.x = g_ORIGX;
  }
  newTextView = [[TextView alloc] initFrame:&gRect];
  [[newTextView window] setDelegate:self];     
  window_number  = window_number + 1;
  sprintf(data, " Grid Data %d",window_number);
  [[newTextView window] setTitle:data];     

  theTextView = newTextView;

  pboardoutput = [Pasteboard new]; /* get the standard selection pasteboard */

  types[0] = NXAsciiPboardType;
  [pboardoutput declareTypes:types num:1 owner:NULL];

  sprintf(data, " Grid Data Output \n");
  [pboardoutput writeType:types[0] data:data length:strlen(data)+1];
  [[theTextView provideTextObject] paste:self];
  sprintf(data, " ---------------- \n");
  [pboardoutput writeType:types[0] data:data length:strlen(data)+1];
  [[theTextView provideTextObject] paste:self];

  data_stream = NXOpenMemory(NULL,0,NX_WRITEONLY);

  listGrid_Data = YES;
  [self listGridLoad:self];
  if(!listGrid_Data){
    [[newTextView window] close];     
    return self;
  }
  listGrid_Data = NO;

  NXGetMemoryBuffer(data_stream, &s_data, &length, &max_length);

  [pboardoutput declareTypes:&NXAsciiPboardType num:1 owner:self];
  [pboardoutput writeType:NXAsciiPboardType data:s_data length:length];
  NXCloseMemory(data_stream, NX_TRUNCATEBUFFER);

  [[theTextView provideTextObject] paste:self];

  return self;
}

#define f_ORIGX 200.0
#define f_ORIGY 150.0
static NXRect fRect = {{f_ORIGX, f_ORIGY},{500.0,600.0}};
- listFunctionData:sender
{   
  char data[64];
  const char *types[1];
  int length, max_length;
  char *s_data;
  static int window_number = 0;
  id newTextView;

  NXOffsetRect(&fRect, 20.0, -20.0);
  if (fRect.origin.y < 0) {
    fRect.origin.y = f_ORIGY;
    fRect.origin.x = f_ORIGX;
  }
  newTextView = [[TextView alloc] initFrame:&fRect];
  [[newTextView window] setDelegate:self];     
  window_number  = window_number + 1;
  sprintf(data, " Function Data %d",window_number);
  [[newTextView window] setTitle:data];     
//  [[newTextView window] setTitle:"FUNCTION"];     

  theTextView = newTextView;

  pboardoutput = [Pasteboard new]; /* get the standard selection pasteboard */

  types[0] = NXAsciiPboardType;
  [pboardoutput declareTypes:types num:1 owner:NULL];

  sprintf(data, " Function Data Output \n");
  [pboardoutput writeType:types[0] data:data length:strlen(data)+1];
  [[theTextView provideTextObject] paste:self];
  sprintf(data, " ---------------- \n");
  [pboardoutput writeType:types[0] data:data length:strlen(data)+1];
  [[theTextView provideTextObject] paste:self];

  data_stream = NXOpenMemory(NULL,0,NX_WRITEONLY);

  listSolution_Data = NO;
  listFunction_Data = YES;
  [self listFunction_SolutionLoad:self];
  // ask the text object to do a paste operation
  if(!listFunction_Data){
    [[newTextView window] close];     
    return self;
  }
  listFunction_Data = NO;

  NXGetMemoryBuffer(data_stream, &s_data, &length, &max_length);

  [pboardoutput declareTypes:&NXAsciiPboardType num:1 owner:self];
  [pboardoutput writeType:NXAsciiPboardType data:s_data length:length];
  NXCloseMemory(data_stream, NX_TRUNCATEBUFFER);

  [[theTextView provideTextObject] paste:self];

  return self;
}

#define s_ORIGX 100.0
#define s_ORIGY 100.0
static NXRect sRect = {{s_ORIGX, s_ORIGY},{1000.0,600.0}};
- listSolutionData:sender
{   
  char data[64];
  const char *types[1];
  int length, max_length;
  char *s_data;
  static int window_number = 0;

  id newTextView;

  NXOffsetRect(&sRect, 20.0, -20.0);
  if (sRect.origin.y < 0) {
    sRect.origin.y = s_ORIGY;
    sRect.origin.x = s_ORIGX;
  }
  newTextView = [[TextView alloc] initFrame:&sRect];
  [[newTextView window] setDelegate:self];     
  window_number  = window_number + 1;
  sprintf(data, " Solution Data %d",window_number);
  [[newTextView window] setTitle:data];     
//  [[newTextView window] setTitle:"SOLUTION"];     

  theTextView = newTextView;

  pboardoutput = [Pasteboard new]; /* get the standard selection pasteboard */

  types[0] = NXAsciiPboardType;
  [pboardoutput declareTypes:types num:1 owner:NULL];

  sprintf(data, " Solution Data Output \n");
  [pboardoutput writeType:types[0] data:data length:strlen(data)+1];
  [[theTextView provideTextObject] paste:self];
  sprintf(data, " ---------------- \n");
  [pboardoutput writeType:types[0] data:data length:strlen(data)+1];
  [[theTextView provideTextObject] paste:self];

  data_stream = NXOpenMemory(NULL,0,NX_WRITEONLY);

  listFunction_Data = NO;
  listSolution_Data = YES;
  [self listFunction_SolutionLoad:self];
  // ask the text object to do a paste operation
  if(!listSolution_Data){
    [[newTextView window] close];     
    return self;
  }
  listSolution_Data = NO;

  NXGetMemoryBuffer(data_stream, &s_data, &length, &max_length);

  [pboardoutput declareTypes:&NXAsciiPboardType num:1 owner:self];
  [pboardoutput writeType:NXAsciiPboardType data:s_data length:length];
  NXCloseMemory(data_stream, NX_TRUNCATEBUFFER);

  [[theTextView provideTextObject] paste:self];

  return self;
}

- listGridLoad:sender
{
  int  j, k, l, i, ii;
  int  jmax = gridhunk.jmax;
  int  kmax = gridhunk.kmax;
  int j_0,j_i,j_m,k_0,k_i,k_m,l_0,l_i,l_m;
  int planeChoice = [chooseGridPlane selectedRow];
  BOOL b_2D = [self do2D3D];
  int total_points = 100, errorAlert = 0;

  /* failsafe for 2d/3d */
  if(b_2D){
    if(planeChoice != 2){
      NXBeep(); beepError = 12;
      planeChoice = 2;
      [chooseGridPlane selectCellAt:planeChoice:0];
    }
  }


  /* shift indices down 1  */
  j_0 = [jGridMin intValueAt:0] - 1;
  j_i = [jGridInc intValueAt:0];
  j_m = [jGridMax intValueAt:0] - 1;

  k_0 = [kGridMin intValueAt:0] - 1;
  k_i = [kGridInc intValueAt:0];
  k_m = [kGridMax intValueAt:0] - 1;

  l_0 = [lGridMin intValueAt:0] - 1;
  l_i = [lGridInc intValueAt:0];
  l_m = [lGridMax intValueAt:0] - 1;
  

  /* failsafe, j or k can never be <=0 || >= max*/
  if(j_i <= 0 || j_i > gridhunk.jmax){
    NXBeep();  beepError = 20;
    j_i = 1;
    [jGridInc setIntValue:j_i at:0];
  }
  if(j_0 < 0 || j_0 > gridhunk.jmax-1){
    NXBeep();  beepError = 20;
    j_0 = 0;
    [jGridMin setIntValue:j_0+1 at:0];
  }
  if(j_m < 0 || j_m > gridhunk.jmax-1){
    NXBeep();  beepError = 20;
    j_m = gridhunk.jmax-1;
    [jGridMax setIntValue:j_m+1 at:0];
  }
  if(j_m < j_0 && planeChoice != 0){
    NXBeep();  beepError = 20;
    j_0 = 0;
    [jGridMin setIntValue:j_0+1 at:0];
    j_m = gridhunk.jmax-1;
    [jGridMax setIntValue:j_m+1 at:0];
  }
  
  if(k_i <= 0 || k_i > gridhunk.kmax){
    NXBeep();  beepError = 20;
    k_i = 1;
    [kGridInc setIntValue:k_i at:0];
  }
  if(k_0 < 0 || k_0 > gridhunk.kmax-1){
    NXBeep();  beepError = 20;
    k_0 = 0;
    [kGridMin setIntValue:k_0+1 at:0];
  }
  if(k_m < 0 || k_m > gridhunk.kmax-1){
    NXBeep();  beepError = 20;
    k_m = gridhunk.kmax-1;
    [kGridMax setIntValue:k_m+1 at:0];
  }
  if(k_m < k_0 && planeChoice != 1){
    NXBeep();  beepError = 20;
    k_0 = 0;
    [kGridMin setIntValue:k_0+1 at:0];
    k_m = gridhunk.kmax-1;
    [kGridMax setIntValue:k_m+1 at:0];
  }
  
  if(l_i <= 0 || l_i > gridhunk.lmax){
    NXBeep();  beepError = 20;
    l_i = 1;
    [lGridInc setIntValue:l_i at:0];
  }
  if(l_0 < 0 || l_0 > gridhunk.lmax-1){
    NXBeep();  beepError = 20;
    l_0 = 0;
    [lGridMin setIntValue:l_0+1 at:0];
  }
  if(l_m < 0 || l_m > gridhunk.lmax-1){
    NXBeep();  beepError = 20;
    l_m = gridhunk.lmax-1;
    [lGridMax setIntValue:l_m+1 at:0];
  }
  if(l_m < l_0 && planeChoice != 2){
    NXBeep();  beepError = 20;
    l_0 = 0;
    [lGridMin setIntValue:l_0+1 at:0];
    l_m = gridhunk.lmax-1;
    [lGridMax setIntValue:l_m+1 at:0];
  }

  total_points = ((j_m-j_0 + 1)/j_i)*((k_m-k_0 + 1)/k_i)*((l_m-l_0 + 1)/l_i);
  if(total_points > 100){
    NXBeep();	beepError = 28;		/* audible alert */
    errorAlert = 
      NXRunAlertPanel("The Number of Lines > 100", 
		      "Number of Lines Of Data Exceeds 100 : You Can \n  Abort or Proceed (with possibly a Long Wait)", 
		      "Continue?","ABORT?",NULL);
    if(errorAlert  == NX_ALERTALTERNATE){ listGrid_Data = NO; return self;}
  }
  if(total_points == 0){
    NXBeep();	beepError = 28;		/* audible alert */
    errorAlert = 
      NXRunAlertPanel("The Number of Lines = 0", 
		      "Make Sure Grid Is Available: You Can \n  Abort or Proceed (with possibly a Long Wait)", 
		      "Continue?","ABORT?",NULL);
    if(errorAlert  == NX_ALERTALTERNATE){ listGrid_Data = NO; return self;}
  }

  if(b_2D){
    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  if(ii%100==0)
	    NXPrintf(data_stream, 
		     "\n   j    k    l         x               y \n");
	  i = l*jmax*kmax + k*jmax + j;
	  NXPrintf(data_stream, "%4d %4d %4d %16.10f %16.10f \n",
		   j+1,k+1,l+1,gridhunk.x[i],gridhunk.y[i]);
	  ii = ii+1;
	}
      }
    }
  }

  if(!b_2D){
    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  if(ii%100==0)NXPrintf
	    (data_stream, 
	     "\n   j    k    l         x               y              z\n");
	  i = l*jmax*kmax + k*jmax + j;
	  NXPrintf(data_stream, "%4d %4d %4d %16.10f %16.10f %16.10f\n",
		   j+1,k+1,l+1,gridhunk.x[i],gridhunk.y[i],gridhunk.z[i]);
	  ii = ii+1;
	}
      }
    }
  }

  return self;
}

- listFunction_SolutionLoad:sender
{
  int  j, k, l, i, ii, n;
  int  jmax = solnhunk.jmax;
  int  kmax = solnhunk.kmax;
  int j_0,j_i,j_m,k_0,k_i,k_m,l_0,l_i,l_m;
  int planeChoice = [chooseFunctionPlane selectedRow];
  int functionChoice = [functionMatrix selectedRow];
  BOOL b_2D = [self do2D3D];
  BOOL aero = [self doAeroDynamics];
  float gamma = 1.4;
  int numberofpoints;
  int total_points = 100, errorAlert = 0;
  
  numberofpoints = solnhunk.jmax*solnhunk.kmax*solnhunk.lmax;

  /* failsafes for 2d/3d multiple vrs single functions*/

  if(!aero && functionChoice+1 > number_Of_Functions_Read_In ){
    NXBeep();	beepError = 13;		/* audible alert */
    functionChoice = 0;
    [functionMatrix selectCellAt:functionChoice:0];
  }

  if(aero){
    if((number_Of_Functions_Read_In != 4 && b_2D) ||
       (number_Of_Functions_Read_In != 5 && !b_2D)){
      if(functionChoice+1 > number_Of_Functions_Read_In ){
	NXBeep();	beepError = 13;		/* audible alert */
	functionChoice = 0;
	[functionMatrix selectCellAt:functionChoice:0];
      }
    }
  }

  if(b_2D){
    if((functionChoice == 3 || functionChoice == 10 )
       && (aero && number_Of_Functions_Read_In == 4)){
      NXBeep();	beepError = 14;	/* audible alert */
      functionChoice = 0;
      [functionMatrix selectCellAt:functionChoice:0];
    }
    if(planeChoice != 2){
      NXBeep(); beepError = 16;
      planeChoice = 2;
      [chooseFunctionPlane selectCellAt:planeChoice:0];
    }
  }


  /* shift indices down 1  */
  j_0 = [jFunctionMin intValueAt:0] - 1;
  j_i = [jFunctionInc intValueAt:0];
  j_m = [jFunctionMax intValueAt:0] - 1;

  k_0 = [kFunctionMin intValueAt:0] - 1;
  k_i = [kFunctionInc intValueAt:0];
  k_m = [kFunctionMax intValueAt:0] - 1;

  l_0 = [lFunctionMin intValueAt:0] - 1;
  l_i = [lFunctionInc intValueAt:0];
  l_m = [lFunctionMax intValueAt:0] - 1;
  

  /* failsafe, j or k can never be <=0 || >= max*/
  if(j_i <= 0 || j_i > solnhunk.jmax){
    NXBeep();  beepError = 21;
    j_i = 1;
    [jFunctionInc setIntValue:j_i at:0];
  }
  if(j_0 < 0 || j_0 > solnhunk.jmax-1){
    NXBeep();  beepError = 21;
    j_0 = 0;
    [jFunctionMin setIntValue:j_0+1 at:0];
  }
  if(j_m < 0 || j_m > solnhunk.jmax-1){
    NXBeep();  beepError = 21;
    j_m = solnhunk.jmax-1;
    [jFunctionMax setIntValue:j_m+1 at:0];
  }
  if(j_m < j_0 && planeChoice != 0){
    NXBeep();  beepError = 21;
    j_0 = 0;
    [jFunctionMin setIntValue:j_0+1 at:0];
    j_m = solnhunk.jmax-1;
    [jFunctionMax setIntValue:j_m+1 at:0];
  }
  
  if(k_i <= 0 || k_i > solnhunk.kmax){
    NXBeep();  beepError = 21;
    k_i = 1;
    [kFunctionInc setIntValue:k_i at:0];
  }
  if(k_0 < 0 || k_0 > solnhunk.kmax-1){
    NXBeep();  beepError = 21;
    k_0 = 0;
    [kFunctionMin setIntValue:k_0+1 at:0];
  }
  if(k_m < 0 || k_m > solnhunk.kmax-1){
    NXBeep();  beepError = 21;
    k_m = solnhunk.kmax-1;
    [kFunctionMax setIntValue:k_m+1 at:0];
  }
  if(k_m < k_0 && planeChoice != 1){
    NXBeep();  beepError = 21;
    k_0 = 0;
    [kFunctionMin setIntValue:k_0+1 at:0];
    k_m = solnhunk.kmax-1;
    [kFunctionMax setIntValue:k_m+1 at:0];
  }
  
  if(l_i <= 0 || l_i > solnhunk.lmax){
    NXBeep();  beepError = 21;
    l_i = 1;
    [lFunctionInc setIntValue:l_i at:0];
  }
  if(l_0 < 0 || l_0 > solnhunk.lmax-1){
    NXBeep();  beepError = 21;
    l_0 = 0;
    [lFunctionMin setIntValue:l_0+1 at:0];
  }
  if(l_m < 0 || l_m > solnhunk.lmax-1){
    NXBeep();  beepError = 21;
    l_m = solnhunk.lmax-1;
    [lFunctionMax setIntValue:l_m+1 at:0];
  }
  if(l_m < l_0 && planeChoice != 2){
    NXBeep();  beepError = 21;
    l_0 = 0;
    [lFunctionMin setIntValue:l_0+1 at:0];
    l_m = solnhunk.lmax-1;
    [lFunctionMax setIntValue:l_m+1 at:0];
  }

  total_points = ((j_m-j_0 + 1)/j_i)*((k_m-k_0 + 1)/k_i)*((l_m-l_0 + 1)/l_i);
  if(total_points > 100){
    NXBeep();	beepError = 28;		/* audible alert */
    errorAlert = NXRunAlertPanel("The Number of Lines > 100", 
				 "Number of Lines Of Data Exceeds 100 : You Can \n  Abort or Proceed (with possibly a Long Wait)", 
				 "Continue?","ABORT?",NULL);
    if(errorAlert  == NX_ALERTALTERNATE)
      { listFunction_Data = NO; listSolution_Data = NO; return self;}
  }
  if(total_points == 0){
    NXBeep();	beepError = 28;		/* audible alert */
    errorAlert = NXRunAlertPanel("The Number of Lines  = 0", 
				 "Make Sure Data Is Available : You Can \n  Abort or Proceed (with possibly a Long Wait)", 
				 "Continue?","ABORT?",NULL);
    if(errorAlert  == NX_ALERTALTERNATE)
      { listFunction_Data = NO; listSolution_Data = NO; return self;}
  }

  if(listFunction_Data){

    if(aero){
      switch(functionChoice){
      case 0:
	ii = 0;
	for (l = l_0; l <= l_m; l= l + l_i){
	  for (k = k_0; k <= k_m; k= k + k_i){
	    for (j = j_0; j <= j_m; j = j + j_i){
	      if(ii%100==0)
		NXPrintf(data_stream, "\n   j    k    l     Density    \n");
	      i = l*jmax*kmax + k*jmax + j;
	      NXPrintf(data_stream, 
		       "%4d %4d %4d %16.10f \n",
		       j+1,k+1,l+1,solnhunk.functions[i]);
	      ii = ii+1;
	    }
	  }
	}
	break;
      case 1:
	ii = 0;
	for (l = l_0; l <= l_m; l= l + l_i){
	  for (k = k_0; k <= k_m; k= k + k_i){
	    for (j = j_0; j <= j_m; j = j + j_i){
	      if(ii%100==0)
		NXPrintf(data_stream, "\n   j    k    l     U Momentum   \n");
	      i = l*jmax*kmax + k*jmax + j;
	      NXPrintf(data_stream, 
		       "%4d %4d %4d %16.10f \n",
		       j+1,k+1,l+1,solnhunk.functions[i+numberofpoints]);
	      ii = ii+1;
	    }
	  }
	}
	break;
      case 2:
	ii = 0;
	for (l = l_0; l <= l_m; l= l + l_i){
	  for (k = k_0; k <= k_m; k= k + k_i){
	    for (j = j_0; j <= j_m; j = j + j_i){
	      if(ii%100==0)
		NXPrintf(data_stream, "\n   j    k    l     V Momentum   \n");
	      i = l*jmax*kmax + k*jmax + j;
	      NXPrintf(data_stream, 
		       "%4d %4d %4d %16.10f \n",
		       j+1,k+1,l+1,solnhunk.functions[i+2*numberofpoints]);
	      ii = ii+1;
	    }
	  }
	}
	break;
      case 3:
	ii = 0;
	for (l = l_0; l <= l_m; l= l + l_i){
	  for (k = k_0; k <= k_m; k= k + k_i){
	    for (j = j_0; j <= j_m; j = j + j_i){
	      if(ii%100==0)
		NXPrintf(data_stream, "\n   j    k    l     W Momentum   \n");
	      i = l*jmax*kmax + k*jmax + j;
	      NXPrintf(data_stream, 
		       "%4d %4d %4d %16.10f \n",
		       j+1,k+1,l+1,solnhunk.functions[i+3*numberofpoints]);
	      ii = ii+1;
	    }
	  }
	}
	break;
      case 4:
	ii = 0;
	for (l = l_0; l <= l_m; l= l + l_i){
	  for (k = k_0; k <= k_m; k= k + k_i){
	    for (j = j_0; j <= j_m; j = j + j_i){
	      if(ii%100==0)
		NXPrintf(data_stream, "\n   j    k    l     Energy   \n");
	      i = l*jmax*kmax + k*jmax + j;
	      if(!b_2D)NXPrintf(data_stream, 
		       "%4d %4d %4d %16.10f \n",
		       j+1,k+1,l+1,solnhunk.functions[i+4*numberofpoints]);
	      if(b_2D)NXPrintf(data_stream, 
		       "%4d %4d %4d %16.10f \n",
		       j+1,k+1,l+1,solnhunk.functions[i+3*numberofpoints]);
	      ii = ii+1;
	    }
	  }
	}
	break;
      case 5:
	ii = 0;
	for (l = l_0; l <= l_m; l= l + l_i){
	  for (k = k_0; k <= k_m; k= k + k_i){
	    for (j = j_0; j <= j_m; j = j + j_i){
	      if(ii%100==0)
		NXPrintf(data_stream, "\n   j    k    l     Mach Number   \n");
	      i = l*jmax*kmax + k*jmax + j;
	      NXPrintf(data_stream, 
		       "%4d %4d %4d %16.10f \n",
		       j+1,k+1,l+1,solnhunk.mach_number[i]);
	      ii = ii+1;
	    }
	  }
	}
	break;
      case 6:
	ii = 0;
	for (l = l_0; l <= l_m; l= l + l_i){
	  for (k = k_0; k <= k_m; k= k + k_i){
	    for (j = j_0; j <= j_m; j = j + j_i){
	      if(ii%100==0)
		NXPrintf(data_stream, "\n   j    k    l     Pressure   \n");
	      i = l*jmax*kmax + k*jmax + j;
	      NXPrintf(data_stream, 
		       "%4d %4d %4d %16.10f \n",
		       j+1,k+1,l+1,solnhunk.pressure[i]);
	      ii = ii+1;
	    }
	  }
	}
	break;
      case 7:
	ii = 0;
	for (l = l_0; l <= l_m; l= l + l_i){
	  for (k = k_0; k <= k_m; k= k + k_i){
	    for (j = j_0; j <= j_m; j = j + j_i){
	      if(ii%100==0)
		NXPrintf(data_stream, "\n   j    k    l     Cp   \n");
	      i = l*jmax*kmax + k*jmax + j;
	      NXPrintf(data_stream, 
		       "%4d %4d %4d %16.10f \n",
		       j+1,k+1,l+1,
		       2.0/(gamma*solnhunk.fsmach*solnhunk.fsmach) * 
		       (solnhunk.pressure[i]*gamma - 1.));
	      ii = ii+1;
	    }
	  }
	}
	break;
      case 8:
	ii = 0;
	for (l = l_0; l <= l_m; l= l + l_i){
	  for (k = k_0; k <= k_m; k= k + k_i){
	    for (j = j_0; j <= j_m; j = j + j_i){
	      if(ii%100==0)
		NXPrintf(data_stream, "\n   j    k    l     U Velocity   \n");
	      i = l*jmax*kmax + k*jmax + j;
	      NXPrintf(data_stream, 
		       "%4d %4d %4d %16.10f \n",
		       j+1,k+1,l+1,
		       solnhunk.functions[i+numberofpoints]/
		       solnhunk.functions[i]);
	      ii = ii+1;
	    }
	  }
	}
	break;
      case 9:
	ii = 0;
	for (l = l_0; l <= l_m; l= l + l_i){
	  for (k = k_0; k <= k_m; k= k + k_i){
	    for (j = j_0; j <= j_m; j = j + j_i){
	      if(ii%100==0)
		NXPrintf(data_stream, "\n   j    k    l     V Velocity   \n");
	      i = l*jmax*kmax + k*jmax + j;
	      NXPrintf(data_stream, 
		       "%4d %4d %4d %16.10f \n",
		       j+1,k+1,l+1,
		       solnhunk.functions[i+2*numberofpoints]
		       /solnhunk.functions[i]);
	      ii = ii+1;
	    }
	  }
	}
	break;
      case 10:
	ii = 0;
	for (l = l_0; l <= l_m; l= l + l_i){
	  for (k = k_0; k <= k_m; k= k + k_i){
	    for (j = j_0; j <= j_m; j = j + j_i){
	      if(ii%100==0)
		NXPrintf(data_stream, "\n   j    k    l     W Velocity   \n");
	      i = l*jmax*kmax + k*jmax + j;
	      NXPrintf(data_stream, 
		       "%4d %4d %4d %16.10f \n",
		       j+1,k+1,l+1,
		       solnhunk.functions[i+3*numberofpoints]/
		       solnhunk.functions[i]);
	      ii = ii+1;
	    }
	  }
	}
	break;
      }
    }
    if(!aero){
      ii = 0;
      for (l = l_0; l <= l_m; l= l + l_i){
	for (k = k_0; k <= k_m; k= k + k_i){
	  for (j = j_0; j <= j_m; j = j + j_i){
	      if(ii%100==0)
		NXPrintf(data_stream, "\n   j    k    l     Function %d \n",
			 functionChoice+1);
	    i = l*jmax*kmax + k*jmax + j;
	    NXPrintf(data_stream, 
		     "%4d %4d %4d %16.10f \n",
		     j+1,k+1,l+1,
		     solnhunk.functions[i+functionChoice*numberofpoints]);
	    ii = ii+1;
	  }
	}
      }
    }
  }

  if(listSolution_Data && b_2D && aero){
    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  if(ii%100==0)NXPrintf(data_stream, 
		     "\n   j    k    l         Q1               Q2             Q3             Q4\n");
	  i = l*jmax*kmax + k*jmax + j;
	  NXPrintf(data_stream, 
		   "%4d %4d %4d %16.10f %16.10f %16.10f %16.10f\n",
		   j+1,k+1,l+1,
		   solnhunk.functions[i],
		   solnhunk.functions[i+numberofpoints],
		   solnhunk.functions[i+numberofpoints*2],
		   solnhunk.functions[i+numberofpoints*3]);
	  ii = ii+1;
	}
      }
    }
  }

  if(listSolution_Data && !b_2D && aero){
    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  if(ii%100==0)NXPrintf(data_stream, 
		     "\n   j    k    l         Q1               Q2             Q3             Q4             Q5\n");
	  i = l*jmax*kmax + k*jmax + j;
	  NXPrintf(data_stream, 
		   "%4d %4d %4d %16.10f %16.10f %16.10f %16.10f %16.10f\n",
		   j+1,k+1,l+1,
		   solnhunk.functions[i],
		   solnhunk.functions[i+numberofpoints],
		   solnhunk.functions[i+numberofpoints*2],
		   solnhunk.functions[i+numberofpoints*3],
		   solnhunk.functions[i+numberofpoints*4]);
	  ii = ii+1;
	}
      }
    }
  }
  if(listSolution_Data && !aero){
    ii = 0;
    for (l = l_0; l <= l_m; l= l + l_i){
      for (k = k_0; k <= k_m; k= k + k_i){
	for (j = j_0; j <= j_m; j = j + j_i){
	  if(ii%100==0)NXPrintf(data_stream, 
		     "\n   n    j    k    l  \n");
	  i = l*jmax*kmax + k*jmax + j;	  
	  for(n = 0; n < number_Of_Functions_Read_In; n = n+1){
	    NXPrintf(data_stream, 
		     "Q %4d %4d %4d %4d %16.10f \n",
		     n+1, j+1,k+1,l+1,solnhunk.functions[i+numberofpoints*n]);
	  }
	  ii = ii+1;
	}
      }
    }
  }

  return self;
}

- setWindowSize:sender
{
  NXRect fullFrame,currentFrame;
  
  NXSetRect(&fullFrame, 114.0, 0.0, 930.0, 830.0);

  [canvasWindow getFrame:&currentFrame];

  if(!NXEqualRect(&currentFrame, &fullFrame))[canvasWindow getFrame:&oldFrame];

  if([chooseScreenSize state])[canvasWindow placeWindow:&fullFrame];
  if(![chooseScreenSize state])[canvasWindow placeWindow:&oldFrame];

  [canvasWindow orderFront:self];

  [self drawPlotButton:1];	/* display "Plotting" */
  [canvas display];
  [self drawPlotButton:0];	/* display "Plot" */

  return self;
}

@end

